[MERGE] with trunk.
bzr revid: nco@tinyerp.com-20130722055239-i7n2usc9bzf4b7uq
This commit is contained in:
commit
da70124909
|
@ -719,7 +719,7 @@ class account_journal(osv.osv):
|
|||
'user_id': fields.many2one('res.users', 'User', help="The user responsible for this journal"),
|
||||
'groups_id': fields.many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', 'Groups'),
|
||||
'currency': fields.many2one('res.currency', 'Currency', help='The currency used to enter statement'),
|
||||
'entry_posted': fields.boolean('Skip \'Draft\' State for Manual Entries', help='Check this box if you don\'t want new journal entries to pass through the \'draft\' state and instead goes directly to the \'posted state\' without any manual validation. \nNote that journal entries that are automatically created by the system are always skipping that state.'),
|
||||
'entry_posted': fields.boolean('Autopost Created Moves', help='Check this box to automatically post entries of this journal. Note that legally, some entries may be automatically posted when the source document is validated (Invoices), whatever the status of this field.'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True, select=1, help="Company related to this journal"),
|
||||
'allow_date':fields.boolean('Check Date in Period', help= 'If set to True then do not accept the entry if the entry date is not into the period dates'),
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,7 +17,7 @@ By far the most beautiful and full featured accounting software. OpenERP Account
|
|||
Activate features on demand, from integrated analytic accounting to budget, assets and multiple companies consolidation.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=account" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2013-04-26 16:01+0000\n"
|
||||
"PO-Revision-Date: 2013-07-10 09:54+0000\n"
|
||||
"Last-Translator: Els Van Vossel (Agaplan) <Unknown>\n"
|
||||
"Language-Team: Els Van Vossel\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-04-27 05:44+0000\n"
|
||||
"X-Generator: Launchpad (build 16580)\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-11 05:17+0000\n"
|
||||
"X-Generator: Launchpad (build 16696)\n"
|
||||
"Language: nl\n"
|
||||
|
||||
#. module: account_voucher
|
||||
|
@ -28,7 +28,7 @@ msgid "account.config.settings"
|
|||
msgstr "account.config.settings"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:369
|
||||
#: code:addons/account_voucher/account_voucher.py:417
|
||||
#, python-format
|
||||
msgid "Write-Off"
|
||||
msgstr "Afschrijving"
|
||||
|
@ -132,7 +132,7 @@ msgid "Voucher Statistics"
|
|||
msgstr "Boekingsstatistieken"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1547
|
||||
#: code:addons/account_voucher/account_voucher.py:1641
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You can not change the journal as you already reconciled some statement "
|
||||
|
@ -233,8 +233,8 @@ msgid "Journal Item"
|
|||
msgstr "Boekingslijn"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:508
|
||||
#: code:addons/account_voucher/account_voucher.py:981
|
||||
#: code:addons/account_voucher/account_voucher.py:558
|
||||
#: code:addons/account_voucher/account_voucher.py:1073
|
||||
#, python-format
|
||||
msgid "Error!"
|
||||
msgstr "Fout"
|
||||
|
@ -261,7 +261,7 @@ msgid "Cancelled"
|
|||
msgstr "Geannuleerd"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1153
|
||||
#: code:addons/account_voucher/account_voucher.py:1249
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You have to configure account base code and account tax code on the '%s' tax!"
|
||||
|
@ -313,7 +313,7 @@ msgid "Tax"
|
|||
msgstr "Btw"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:879
|
||||
#: code:addons/account_voucher/account_voucher.py:971
|
||||
#, python-format
|
||||
msgid "Invalid Action!"
|
||||
msgstr "Ongeldige actie"
|
||||
|
@ -366,10 +366,10 @@ msgid "Import Invoices"
|
|||
msgstr "Facturen importeren"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1112
|
||||
#: code:addons/account_voucher/account_voucher.py:1208
|
||||
#, python-format
|
||||
msgid "Wrong voucher line"
|
||||
msgstr ""
|
||||
msgstr "Verkeerde betalingsregel"
|
||||
|
||||
#. module: account_voucher
|
||||
#: selection:account.voucher,pay_now:0
|
||||
|
@ -385,7 +385,7 @@ msgid "Receipt"
|
|||
msgstr "Reçu"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1018
|
||||
#: code:addons/account_voucher/account_voucher.py:1110
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You should configure the 'Gain Exchange Rate Account' in the accounting "
|
||||
|
@ -409,7 +409,7 @@ msgstr "Periode"
|
|||
|
||||
#. module: account_voucher
|
||||
#: view:account.voucher:0
|
||||
#: code:addons/account_voucher/account_voucher.py:211
|
||||
#: code:addons/account_voucher/account_voucher.py:231
|
||||
#, python-format
|
||||
msgid "Supplier"
|
||||
msgstr "Leverancier"
|
||||
|
@ -430,7 +430,7 @@ msgid "Debit"
|
|||
msgstr "Debet"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1547
|
||||
#: code:addons/account_voucher/account_voucher.py:1641
|
||||
#, python-format
|
||||
msgid "Unable to change journal !"
|
||||
msgstr "Het dagboek kan niet worden gewijzigd"
|
||||
|
@ -469,6 +469,12 @@ msgid ""
|
|||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Klik hier als u een nieuwe leveranciersbetaling wilt maken.\n"
|
||||
" </p><p>\n"
|
||||
" Met OpenERP kunt u betalingen aan leveranciers opvolgen.\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
|
||||
#. module: account_voucher
|
||||
#: view:account.voucher:0
|
||||
|
@ -536,7 +542,7 @@ msgid "Pay Invoice"
|
|||
msgstr "Factuur betalen"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1153
|
||||
#: code:addons/account_voucher/account_voucher.py:1249
|
||||
#, python-format
|
||||
msgid "No Account Base Code and Account Tax Code!"
|
||||
msgstr "Geen rekening voor basisvak en btw-vak"
|
||||
|
@ -590,15 +596,15 @@ msgid "To Review"
|
|||
msgstr "Te controleren"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1025
|
||||
#: code:addons/account_voucher/account_voucher.py:1039
|
||||
#: code:addons/account_voucher/account_voucher.py:1194
|
||||
#: code:addons/account_voucher/account_voucher.py:1120
|
||||
#: code:addons/account_voucher/account_voucher.py:1134
|
||||
#: code:addons/account_voucher/account_voucher.py:1286
|
||||
#, python-format
|
||||
msgid "change"
|
||||
msgstr "wijzigen"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1014
|
||||
#: code:addons/account_voucher/account_voucher.py:1106
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You should configure the 'Loss Exchange Rate Account' in the accounting "
|
||||
|
@ -656,6 +662,7 @@ msgstr "Maand"
|
|||
#. module: account_voucher
|
||||
#: field:account.voucher,currency_id:0
|
||||
#: field:account.voucher.line,currency_id:0
|
||||
#: model:ir.model,name:account_voucher.model_res_currency
|
||||
#: field:sale.receipt.report,currency_id:0
|
||||
msgid "Currency"
|
||||
msgstr "Munt"
|
||||
|
@ -699,7 +706,7 @@ msgid "Reconcile Payment Balance"
|
|||
msgstr "Betalingssaldo afpunten"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:975
|
||||
#: code:addons/account_voucher/account_voucher.py:1067
|
||||
#, python-format
|
||||
msgid "Configuration Error !"
|
||||
msgstr "Configuratiefout"
|
||||
|
@ -764,7 +771,7 @@ msgid "October"
|
|||
msgstr "Oktober"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:976
|
||||
#: code:addons/account_voucher/account_voucher.py:1068
|
||||
#, python-format
|
||||
msgid "Please activate the sequence of selected journal !"
|
||||
msgstr "Gelieve de nummering van het gekozen journaal te activeren."
|
||||
|
@ -844,7 +851,7 @@ msgid "Previous Payments ?"
|
|||
msgstr "Vorige betalingen?"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1112
|
||||
#: code:addons/account_voucher/account_voucher.py:1208
|
||||
#, python-format
|
||||
msgid "The invoice you are willing to pay is not valid anymore."
|
||||
msgstr "De factuur die u wilt betalen, is niet meer geldig."
|
||||
|
@ -876,7 +883,7 @@ msgid "Active"
|
|||
msgstr "Actief"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:982
|
||||
#: code:addons/account_voucher/account_voucher.py:1074
|
||||
#, python-format
|
||||
msgid "Please define a sequence on the journal."
|
||||
msgstr "Gelieve een reeks in te stellen voor het journaal."
|
||||
|
@ -1004,7 +1011,7 @@ msgid "Journal Items"
|
|||
msgstr "Boekingslijnen"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:508
|
||||
#: code:addons/account_voucher/account_voucher.py:558
|
||||
#, python-format
|
||||
msgid "Please define default credit/debit accounts on the journal \"%s\"."
|
||||
msgstr "Stel een standaard debet-/creditrekening in voor journaal \"%s\"."
|
||||
|
@ -1221,7 +1228,7 @@ msgstr ""
|
|||
"Het bedrag van het reçu moet gelijk zijn aan het bedrag op de uittreksellijn."
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:879
|
||||
#: code:addons/account_voucher/account_voucher.py:971
|
||||
#, python-format
|
||||
msgid "Cannot delete voucher(s) which are already opened or paid."
|
||||
msgstr "Een openstaand of betaald reçu kan niet meer worden verwijderd."
|
||||
|
@ -1284,8 +1291,8 @@ msgid "Status <b>changed</b>"
|
|||
msgstr "Status <b>vgewijzigd</b>"
|
||||
|
||||
#. module: account_voucher
|
||||
#: code:addons/account_voucher/account_voucher.py:1014
|
||||
#: code:addons/account_voucher/account_voucher.py:1018
|
||||
#: code:addons/account_voucher/account_voucher.py:1106
|
||||
#: code:addons/account_voucher/account_voucher.py:1110
|
||||
#, python-format
|
||||
msgid "Insufficient Configuration!"
|
||||
msgstr "Niet volledig geconfigureerd"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
automatically based on your activities.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=account_voucher" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -621,7 +621,7 @@ class crm_lead(format_address, osv.osv):
|
|||
attachment.write(values)
|
||||
return True
|
||||
|
||||
def merge_opportunity(self, cr, uid, ids, context=None):
|
||||
def merge_opportunity(self, cr, uid, ids, user_id=False, section_id=False, context=None):
|
||||
"""
|
||||
Different cases of merge:
|
||||
- merge leads together = 1 new lead
|
||||
|
@ -655,6 +655,11 @@ class crm_lead(format_address, osv.osv):
|
|||
fields = list(CRM_LEAD_FIELDS_TO_MERGE)
|
||||
merged_data = self._merge_data(cr, uid, ids, highest, fields, context=context)
|
||||
|
||||
if user_id:
|
||||
merged_data['user_id'] = user_id
|
||||
if section_id:
|
||||
merged_data['section_id'] = section_id
|
||||
|
||||
# Merge messages and attachements into the first opportunity
|
||||
self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context)
|
||||
self._merge_opportunity_attachments(cr, uid, highest.id, tail_opportunities, context=context)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
Manage your sales funnel with no effort. Attract leads, follow-up on phone calls and meetings. Analyse the quality of your leads to make informed decisions and save time by integrating emails directly into the application.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=crm" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -35,6 +35,8 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
|||
('merge', 'Merge with existing opportunities')
|
||||
], 'Conversion Action', required=True),
|
||||
'opportunity_ids': fields.many2many('crm.lead', string='Opportunities'),
|
||||
'user_id': fields.many2one('res.users', 'Salesperson', select=True),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', select=True),
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
|
@ -74,9 +76,27 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
|||
res.update({'name' : len(tomerge) >= 2 and 'merge' or 'convert'})
|
||||
if 'opportunity_ids' in fields and len(tomerge) >= 2:
|
||||
res.update({'opportunity_ids': list(tomerge)})
|
||||
|
||||
if lead.user_id:
|
||||
res.update({'user_id': lead.user_id.id})
|
||||
if lead.section_id:
|
||||
res.update({'section_id': lead.section_id.id})
|
||||
return res
|
||||
|
||||
def on_change_user(self, cr, uid, ids, user_id, section_id, context=None):
|
||||
""" When changing the user, also set a section_id or restrict section id
|
||||
to the ones user_id is member of. """
|
||||
if user_id:
|
||||
if section_id:
|
||||
user_in_section = self.pool.get('crm.case.section').search(cr, uid, [('id', '=', section_id), '|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context, count=True)
|
||||
else:
|
||||
user_in_section = False
|
||||
if not user_in_section:
|
||||
section_id = False
|
||||
section_ids = self.pool.get('crm.case.section').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
|
||||
if section_ids:
|
||||
section_id = section_ids[0]
|
||||
return {'value': {'section_id': section_id}}
|
||||
|
||||
def view_init(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
Check some preconditions before the wizard executes.
|
||||
|
@ -118,15 +138,15 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
|||
w = self.browse(cr, uid, ids, context=context)[0]
|
||||
opp_ids = [o.id for o in w.opportunity_ids]
|
||||
if w.name == 'merge':
|
||||
lead_id = self.pool.get('crm.lead').merge_opportunity(cr, uid, opp_ids, context=context)
|
||||
lead_id = self.pool.get('crm.lead').merge_opportunity(cr, uid, opp_ids, w.user_id.id, w.section_id.id, context=context)
|
||||
lead_ids = [lead_id]
|
||||
lead = self.pool.get('crm.lead').read(cr, uid, lead_id, ['type'], context=context)
|
||||
if lead['type'] == "lead":
|
||||
context.update({'active_ids': lead_ids})
|
||||
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context)
|
||||
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids, 'user_ids': [w.user_id.id], 'section_id': w.section_id.id}, context=context)
|
||||
else:
|
||||
lead_ids = context.get('active_ids', [])
|
||||
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context)
|
||||
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids, 'user_ids': [w.user_id.id], 'section_id': w.section_id.id}, context=context)
|
||||
|
||||
return self.pool.get('crm.lead').redirect_opportunity_view(cr, uid, lead_ids[0], context=context)
|
||||
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
<group name="name">
|
||||
<field name="name" class="oe_inline"/>
|
||||
</group>
|
||||
<group string="Assign opportunities to">
|
||||
<field name="user_id" class="oe_inline" on_change="on_change_user(user_id, section_id, context)"/>
|
||||
<field name="section_id" class="oe_inline"/>
|
||||
</group>
|
||||
<group string="Opportunities">
|
||||
<field name="opportunity_ids" attrs="{'invisible': [('name', '!=', 'merge')]}" nolabel="1">
|
||||
<tree>
|
||||
|
@ -56,6 +60,10 @@
|
|||
attrs="{'required': [('action', '=', 'exist')], 'invisible':[('action','!=','exist')]}"
|
||||
class="oe_inline"/>
|
||||
</group>
|
||||
<group string="Assign opportunities to" attrs="{'invisible': [('name', '=', '')]}">
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="user_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group string="Select Opportunities" attrs="{'invisible': [('name', '!=', 'merge')]}">
|
||||
<field name="opportunity_ids" colspan="4" nolabel="1" attrs="{'invisible': [('name', '=', 'convert')]}">
|
||||
<tree>
|
||||
|
@ -72,12 +80,6 @@
|
|||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
<group string="Assign opportunities to" attrs="{'invisible': [('name', '=', '')]}">
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
<field name="user_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
|
||||
<footer>
|
||||
<button name="mass_convert" string="Convert to Opportunities" type="object" class="oe_highlight"/>
|
||||
or
|
||||
|
|
|
@ -34,6 +34,8 @@ class crm_merge_opportunity(osv.osv_memory):
|
|||
_description = 'Merge opportunities'
|
||||
_columns = {
|
||||
'opportunity_ids': fields.many2many('crm.lead', rel='merge_opportunity_rel', id1='merge_id', id2='opportunity_id', string='Leads/Opportunities'),
|
||||
'user_id': fields.many2one('res.users', 'Salesperson', select=True),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', select=True),
|
||||
}
|
||||
|
||||
def action_merge(self, cr, uid, ids, context=None):
|
||||
|
@ -47,7 +49,7 @@ class crm_merge_opportunity(osv.osv_memory):
|
|||
#TODO: why is this passed through the context ?
|
||||
context['lead_ids'] = [opportunity2merge_ids[0].id]
|
||||
|
||||
merge_id = lead_obj.merge_opportunity(cr, uid, [x.id for x in opportunity2merge_ids], context=context)
|
||||
merge_id = lead_obj.merge_opportunity(cr, uid, [x.id for x in opportunity2merge_ids], wizard.user_id.id, wizard.section_id.id, context=context)
|
||||
|
||||
# The newly created lead might be a lead or an opp: redirect toward the right view
|
||||
merge_result = lead_obj.browse(cr, uid, merge_id, context=context)
|
||||
|
@ -79,4 +81,19 @@ class crm_merge_opportunity(osv.osv_memory):
|
|||
|
||||
return res
|
||||
|
||||
def on_change_user(self, cr, uid, ids, user_id, section_id, context=None):
|
||||
""" When changing the user, also set a section_id or restrict section id
|
||||
to the ones user_id is member of. """
|
||||
if user_id:
|
||||
if section_id:
|
||||
user_in_section = self.pool.get('crm.case.section').search(cr, uid, [('id', '=', section_id), '|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context, count=True)
|
||||
else:
|
||||
user_in_section = False
|
||||
if not user_in_section:
|
||||
section_id = False
|
||||
section_ids = self.pool.get('crm.case.section').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
|
||||
if section_ids:
|
||||
section_id = section_ids[0]
|
||||
return {'value': {'section_id': section_id}}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -8,20 +8,25 @@
|
|||
<field name="model">crm.merge.opportunity</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Merge Leads/Opportunities" version="7.0">
|
||||
<separator string="Select Leads/Opportunities"/>
|
||||
<field name="opportunity_ids">
|
||||
<tree>
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
</tree>
|
||||
</field>
|
||||
<group string="Assign opportunities to">
|
||||
<field name="user_id" class="oe_inline" on_change="on_change_user(user_id, context)"/>
|
||||
<field name="section_id" class="oe_inline"/>
|
||||
</group>
|
||||
<group string="Select Leads/Opportunities">
|
||||
<field name="opportunity_ids" nolabel="1">
|
||||
<tree>
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="section_id" groups="base.group_multi_salesteams"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_merge" type="object" string="Merge" class="oe_highlight"/>
|
||||
or
|
||||
|
|
|
@ -38,7 +38,7 @@ You can also use the geolocalization without using the GPS coordinates.
|
|||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['crm', 'account', 'portal'],
|
||||
'demo': ['res_partner_demo.xml'],
|
||||
'demo': ['res_partner_demo.xml', 'crm_lead_demo.xml'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'res_partner_view.xml',
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Demo Leads -->
|
||||
<record id="crm_case_partner_assign_1" model="crm.lead">
|
||||
<field name="type">lead</field>
|
||||
<field name="name">Specifications and price of your phones</field>
|
||||
<field name="contact_name">Steve Martinez</field>
|
||||
<field name="partner_name"></field>
|
||||
<field name="partner_id" ref=""/>
|
||||
<field name="function">Reseller</field>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field name="city">Edinburgh</field>
|
||||
<field name="type_id" ref="crm.type_lead8"/>
|
||||
<field name="categ_ids" eval="[(6, 0, [ref('crm.categ_oppor1')])]"/>
|
||||
<field name="channel_id" ref="crm.crm_case_channel_email"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="section_id" ref="crm.crm_case_section_2"/>
|
||||
<field name="user_id" ref=""/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field name="description">Hi,
|
||||
|
||||
Please, can you give me more details about your phones, including their specifications and their prices.
|
||||
|
||||
Regards,
|
||||
Steve</field>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="partner_assigned_id" ref="portal.partner_demo_portal"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -16,12 +16,8 @@
|
|||
<field name="user_id"/>
|
||||
|
||||
<field string="Timebox" name="timebox_id"/>
|
||||
<button name="prev_timebox" type="object" icon="gtk-go-back" string="Previous" states="draft,pending,open"/>
|
||||
<button name="next_timebox" type="object" icon="gtk-go-forward" string="Next" states="draft,pending,open"/>
|
||||
|
||||
<field name="state"/>
|
||||
<button name="do_cancel" states="draft,open,pending" string="Cancel" type="object" icon="gtk-cancel" help="For cancelling the task"/>
|
||||
<button name="action_close" states="draft,pending,open" string="Done" type="object" icon="terp-dialog-close" help="For changing to done state"/>
|
||||
<button name="prev_timebox" type="object" string="Previous"/>
|
||||
<button name="next_timebox" type="object" string="Next"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
# Icelandic translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-07-10 12:09+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Icelandic <is@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-11 05:17+0000\n"
|
||||
"X-Generator: Launchpad (build 16696)\n"
|
||||
|
||||
#. module: edi
|
||||
#. openerp-web
|
||||
#: code:addons/edi/static/src/js/edi.js:67
|
||||
#, python-format
|
||||
msgid "Reason:"
|
||||
msgstr "Ástæða:"
|
||||
|
||||
#. module: edi
|
||||
#. openerp-web
|
||||
#: code:addons/edi/static/src/js/edi.js:60
|
||||
#, python-format
|
||||
msgid "The document has been successfully imported!"
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#. openerp-web
|
||||
#: code:addons/edi/static/src/js/edi.js:65
|
||||
#, python-format
|
||||
msgid "Sorry, the document could not be imported."
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: model:ir.model,name:edi.model_res_company
|
||||
msgid "Companies"
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: model:ir.model,name:edi.model_res_currency
|
||||
msgid "Currency"
|
||||
msgstr "Gjaldmiðill"
|
||||
|
||||
#. module: edi
|
||||
#. openerp-web
|
||||
#: code:addons/edi/static/src/js/edi.js:71
|
||||
#, python-format
|
||||
msgid "Document Import Notification"
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: code:addons/edi/models/edi.py:130
|
||||
#, python-format
|
||||
msgid "Missing application."
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: code:addons/edi/models/edi.py:131
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The document you are trying to import requires the OpenERP `%s` application. "
|
||||
"You can install it by connecting as the administrator and opening the "
|
||||
"configuration assistant."
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: code:addons/edi/models/edi.py:47
|
||||
#, python-format
|
||||
msgid "'%s' is an invalid external ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: edi
|
||||
#: model:ir.model,name:edi.model_res_partner
|
||||
msgid "Partner"
|
||||
msgstr "Viðskipta aðili"
|
||||
|
||||
#. module: edi
|
||||
#: model:ir.model,name:edi.model_edi_edi
|
||||
msgid "EDI Subsystem"
|
||||
msgstr ""
|
|
@ -8,20 +8,19 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2013-06-27 16:03+0000\n"
|
||||
"PO-Revision-Date: 2012-12-07 22:47+0000\n"
|
||||
"Last-Translator: Fábio Martinelli - http://zupy.com.br "
|
||||
"<webmaster@guaru.net>\n"
|
||||
"PO-Revision-Date: 2013-07-20 22:32+0000\n"
|
||||
"Last-Translator: Claudio de Araujo Santos <claudioaraujosantos@gmail.com>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-06-28 05:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16681)\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-22 05:34+0000\n"
|
||||
"X-Generator: Launchpad (build 16696)\n"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.ui.menu,name:google_drive.menu_google_drive_config
|
||||
msgid "Google Drive configuration"
|
||||
msgstr ""
|
||||
msgstr "Configuração do Google Drive"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:48
|
||||
|
@ -40,6 +39,13 @@ msgid ""
|
|||
"in your Google Drive and in OpenERP attachment will be named\n"
|
||||
" 'Agrolait_SO0001_Sales'."
|
||||
msgstr ""
|
||||
"O nome do documento em anexo pode usar dados fixos ou variáveis. Para "
|
||||
"distinguir entre documentos\n"
|
||||
" Google Drive, usar palavras fixos e campos. "
|
||||
"Por exemplo, no exemplo acima, se escreveu Agrolait_% (nome) s_Sales\n"
|
||||
" no campo Nome da unidade do Google, o "
|
||||
"documento em seu Google Drive e em OpenERP anexo será nomeado\n"
|
||||
" 'Agrolait_SO0001_Sales \"."
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -47,16 +53,18 @@ msgid ""
|
|||
"- If filter is not specified, link of google document will appear in "
|
||||
"\"More\" option for all users for all opportunities."
|
||||
msgstr ""
|
||||
"- Se o filtro não for especificado, ligação de documento google aparecerá na "
|
||||
"opção \"Mais\" para todos os usuários de todas as oportunidades."
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "To create a new filter:"
|
||||
msgstr ""
|
||||
msgstr "Para criar um novo filtro:"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.model,name:google_drive.model_base_config_settings
|
||||
msgid "base.config.settings"
|
||||
msgstr ""
|
||||
msgstr "base.config.settings"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.actions.act_window,help:google_drive.action_google_drive_users_config
|
||||
|
@ -74,17 +82,30 @@ msgid ""
|
|||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" Clique para adicionar um novo modelo.\n"
|
||||
" </ P>\n"
|
||||
" <p>\n"
|
||||
" Vincular seus próprios modelos Google Drive para "
|
||||
"qualquer registro de OpenERP. Se você tem documentos específicos que você "
|
||||
"realmente deseja que seu colaborador preencher, por exemplo, usar uma "
|
||||
"planilha para controlar a qualidade do seu produto ou rever a lista de "
|
||||
"entrega para cada ordem em um país estrangeiro, ... É muito fácil de "
|
||||
"gerenciá-los, associá-los a OpenERP e usá-los para colaborar com seus "
|
||||
"empregados.\n"
|
||||
" </ P>\n"
|
||||
" "
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:150
|
||||
#, python-format
|
||||
msgid "Incorrect URL!"
|
||||
msgstr ""
|
||||
msgstr "URL incorreto!"
|
||||
|
||||
#. module: google_drive
|
||||
#: view:base.config.settings:0
|
||||
msgid "Configure your templates"
|
||||
msgstr ""
|
||||
msgstr "Configure seus modelos"
|
||||
|
||||
#. module: google_drive
|
||||
#: help:google.drive.config,name_template:0
|
||||
|
@ -92,6 +113,8 @@ msgid ""
|
|||
"Choose how the new google drive will be named, on google side. Eg. "
|
||||
"gdoc_%(field_name)s"
|
||||
msgstr ""
|
||||
"Escolha como a nova unidade google será nomeado, no lado google. Por "
|
||||
"exemplo. gdoc_% (field_name) s"
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -99,6 +122,8 @@ msgid ""
|
|||
"- Go to the OpenERP document you want to filter. For instance, go to "
|
||||
"Opportunities and search on Sales Department."
|
||||
msgstr ""
|
||||
"- Vá para o documento OpenERP você deseja filtrar. Por exemplo, ir para "
|
||||
"Oportunidades e de pesquisa no Departamento de Vendas."
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -106,6 +131,8 @@ msgid ""
|
|||
"- In this \"Search\" view, select the option \"Save Current Filter\", enter "
|
||||
"the name (Ex: Sales Department)"
|
||||
msgstr ""
|
||||
"- Neste ponto de vista \"Pesquisar\", selecione a opção \"Salvar Filtro "
|
||||
"Atual\", digite o nome (Ex: Departamento de Vendas)"
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -114,6 +141,9 @@ msgid ""
|
|||
"\"More\" options will appear for all users in opportunities of Sales "
|
||||
"Department."
|
||||
msgstr ""
|
||||
"- Se você selecionar \"Compartilhar com todos os usuários\", ligação de "
|
||||
"documento google na opção \"Mais\" será exibido para todos os usuários em "
|
||||
"oportunidades do Departamento de Vendas."
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -122,23 +152,28 @@ msgid ""
|
|||
"\"More\" options will not appear for other users in opportunities of Sales "
|
||||
"Department."
|
||||
msgstr ""
|
||||
"- Se você não selecionar \"Compartilhar com todos os usuários\", link do "
|
||||
"documento google em \"More\" opções não aparecerá para outros usuários em "
|
||||
"oportunidades do Departamento de Vendas."
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:48
|
||||
#, python-format
|
||||
msgid "At least one key cannot be found in your Google Drive name pattern"
|
||||
msgstr ""
|
||||
"Pelo menos uma chave não pode ser encontrado em seu padrão de nome de Google "
|
||||
"Drive"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:150
|
||||
#, python-format
|
||||
msgid "Please enter a valid Google Document URL."
|
||||
msgstr ""
|
||||
msgstr "Por favor insira um URL Documento Google válida."
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_client_id:0
|
||||
msgid "Google Client "
|
||||
msgstr ""
|
||||
msgstr "Google Cliente "
|
||||
|
||||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
|
@ -146,43 +181,46 @@ msgid ""
|
|||
"https://docs.google.com/document/d/1vOtpJK9scIQz6taD9tJRIETWbEw3fSiaQHArsJYcu"
|
||||
"a4/edit"
|
||||
msgstr ""
|
||||
"https://docs.google.com/document/d/1vOtpJK9scIQz6taD9tJRIETWbEw3fSiaQHArsJYcu"
|
||||
"a4/edit"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,filter_id:0
|
||||
msgid "Filter"
|
||||
msgstr ""
|
||||
msgstr "Filtro"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,name_template:0
|
||||
msgid "Google Drive Name Pattern"
|
||||
msgstr ""
|
||||
msgstr "Nome Padrão Google Drive"
|
||||
|
||||
#. module: google_drive
|
||||
#: help:base.config.settings,google_drive_uri:0
|
||||
msgid "The URL to generate the authorization code from Google"
|
||||
msgstr ""
|
||||
msgstr "O URL para gerar o código de autorização do Google"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.filters,name:google_drive.filter_partner
|
||||
msgid "Customer"
|
||||
msgstr ""
|
||||
msgstr "Cliente"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_resource_id:0
|
||||
msgid "Resource Id"
|
||||
msgstr ""
|
||||
msgstr "ID Recurso"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:91
|
||||
#, python-format
|
||||
msgid "The Google Template cannot be found. Maybe it has been deleted."
|
||||
msgstr ""
|
||||
"O modelo do Google não pode ser encontrado. Talvez tenha sido excluído."
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.actions.act_window,name:google_drive.action_google_drive_users_config
|
||||
#: model:ir.ui.menu,name:google_drive.menu_google_drive_model_config
|
||||
msgid "Google Drive Templates"
|
||||
msgstr ""
|
||||
msgstr "Templates do Google Drive"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:81
|
||||
|
@ -191,23 +229,25 @@ msgid ""
|
|||
"Something went wrong during the token generation. Please request again an "
|
||||
"authorization code in %(menu:base_setup.menu_general_configuration)s."
|
||||
msgstr ""
|
||||
"Algo deu errado durante a geração de token. Por favor, solicite novamente um "
|
||||
"código de autorização em%(menu:base_setup.menu_general_configuration)s."
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:124
|
||||
#, python-format
|
||||
msgid "Google Drive Error!"
|
||||
msgstr ""
|
||||
msgstr "Google Drive Error!"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:base.config.settings,google_drive_uri:0
|
||||
msgid "URI"
|
||||
msgstr ""
|
||||
msgstr "URL"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:124
|
||||
#, python-format
|
||||
msgid "Creating google drive may only be done by one at a time."
|
||||
msgstr ""
|
||||
msgstr "Criação de unidade google só pode ser feito por um de cada vez."
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,model:0
|
||||
|
@ -218,38 +258,40 @@ msgstr "Modelo"
|
|||
#. module: google_drive
|
||||
#: view:google.drive.config:0
|
||||
msgid "Google Drive Configuration"
|
||||
msgstr ""
|
||||
msgstr "Configuração do acionamento Google"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,name:0
|
||||
msgid "Template Name"
|
||||
msgstr ""
|
||||
msgstr "Nome do modelo"
|
||||
|
||||
#. module: google_drive
|
||||
#: constraint:google.drive.config:0
|
||||
msgid ""
|
||||
"Model of selected filter is not matching with model of current template."
|
||||
msgstr ""
|
||||
"Modelo de filtro selecionado não está combinando com o modelo do modelo "
|
||||
"atual."
|
||||
|
||||
#. module: google_drive
|
||||
#: field:google.drive.config,google_drive_template_url:0
|
||||
msgid "Template URL"
|
||||
msgstr ""
|
||||
msgstr "Modelo de URL"
|
||||
|
||||
#. module: google_drive
|
||||
#: view:base.config.settings:0
|
||||
msgid "and paste it here"
|
||||
msgstr ""
|
||||
msgstr "e cole-o aqui"
|
||||
|
||||
#. module: google_drive
|
||||
#: field:base.config.settings,google_drive_authorization_code:0
|
||||
msgid "Authorization Code"
|
||||
msgstr ""
|
||||
msgstr "Código de Autorização"
|
||||
|
||||
#. module: google_drive
|
||||
#: model:ir.model,name:google_drive.model_google_drive_config
|
||||
msgid "Google Drive templates config"
|
||||
msgstr ""
|
||||
msgstr "Google Drive templates de configuração"
|
||||
|
||||
#. module: google_drive
|
||||
#: code:addons/google_drive/google_drive.py:64
|
||||
|
@ -258,3 +300,6 @@ msgid ""
|
|||
"You haven't configured 'Authorization Code' generated from google, Please "
|
||||
"generate and configure it in %(menu:base_setup.menu_general_configuration)s."
|
||||
msgstr ""
|
||||
"Você não configurou \"Código de Autorização\" gerado a partir do Google, por "
|
||||
"favor, gerar e configurá-lo em "
|
||||
"%(menu:base_setup.menu_general_configuration)s."
|
||||
|
|
|
@ -17,7 +17,7 @@ Get all your HR operations managed easily: knowledge sharing, recruitments, appr
|
|||
Each need is provided by a specific app that you activate on demand.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=hr" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -322,7 +322,7 @@
|
|||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Other Information">
|
||||
<page string="Accounting Information">
|
||||
<group>
|
||||
<group string="Miscellaneous">
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
|
|
|
@ -101,17 +101,19 @@ class LongPollingController(http.Controller):
|
|||
raise Exception("Not usable in a server not running gevent")
|
||||
from openerp.addons.im.watcher import ImWatcher
|
||||
if db is not None:
|
||||
request.session.authenticate(db=db, uid=uid, password=password)
|
||||
openerp.service.security.check(db, uid, password)
|
||||
else:
|
||||
request.session.authenticate(db=request.session._db, uid=request.session._uid, password=request.session._password)
|
||||
uid = request.session.uid
|
||||
db = request.session.db
|
||||
|
||||
with request.registry.cursor() as cr:
|
||||
request.registry.get('im.user').im_connect(cr, request.uid, uuid=uuid, context=request.context)
|
||||
my_id = request.registry.get('im.user').get_by_user_id(cr, request.uid, uuid or request.session._uid, request.context)["id"]
|
||||
registry = openerp.modules.registry.RegistryManager.get(db)
|
||||
with registry.cursor() as cr:
|
||||
registry.get('im.user').im_connect(cr, uid, uuid=uuid, context=request.context)
|
||||
my_id = registry.get('im.user').get_by_user_id(cr, uid, uuid or uid, request.context)["id"]
|
||||
num = 0
|
||||
while True:
|
||||
with request.registry.cursor() as cr:
|
||||
res = request.registry.get('im.message').get_messages(cr, request.uid, last, users_watch, uuid=uuid, context=request.context)
|
||||
with registry.cursor() as cr:
|
||||
res = registry.get('im.message').get_messages(cr, uid, last, users_watch, uuid=uuid, context=request.context)
|
||||
if num >= 1 or len(res["res"]) > 0:
|
||||
return res
|
||||
last = res["last"]
|
||||
|
|
|
@ -37,36 +37,45 @@ env.filters["json"] = json.dumps
|
|||
|
||||
class LiveChatController(http.Controller):
|
||||
|
||||
@http.route('/im_livechat/loader')
|
||||
def _auth(self, db):
|
||||
reg = openerp.modules.registry.RegistryManager.get(db)
|
||||
uid = openerp.netsvc.dispatch_rpc('common', 'authenticate', [db, "anonymous", "anonymous", None])
|
||||
return reg, uid
|
||||
|
||||
@http.route('/im_livechat/loader', auth="none")
|
||||
def loader(self, **kwargs):
|
||||
p = json.loads(kwargs["p"])
|
||||
db = p["db"]
|
||||
channel = p["channel"]
|
||||
user_name = p.get("user_name", None)
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
info = request.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
info["db"] = db
|
||||
info["channel"] = channel
|
||||
info["userName"] = user_name
|
||||
return request.make_response(env.get_template("loader.js").render(info),
|
||||
headers=[('Content-Type', "text/javascript")])
|
||||
|
||||
@http.route('/im_livechat/web_page')
|
||||
reg, uid = self._auth(db)
|
||||
with reg.cursor() as cr:
|
||||
info = reg.get('im_livechat.channel').get_info_for_chat_src(cr, uid, channel)
|
||||
info["db"] = db
|
||||
info["channel"] = channel
|
||||
info["userName"] = user_name
|
||||
return request.make_response(env.get_template("loader.js").render(info),
|
||||
headers=[('Content-Type', "text/javascript")])
|
||||
|
||||
@http.route('/im_livechat/web_page', auth="none")
|
||||
def web_page(self, **kwargs):
|
||||
p = json.loads(kwargs["p"])
|
||||
db = p["db"]
|
||||
channel = p["channel"]
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
script = request.session.model('im_livechat.channel').read(channel, ["script"])["script"]
|
||||
info = request.session.model('im_livechat.channel').get_info_for_chat_src(channel)
|
||||
info["script"] = script
|
||||
return request.make_response(env.get_template("web_page.html").render(info),
|
||||
headers=[('Content-Type', "text/html")])
|
||||
reg, uid = self._auth(db)
|
||||
with reg.cursor() as cr:
|
||||
script = reg.get('im_livechat.channel').read(cr, uid, channel, ["script"])["script"]
|
||||
info = reg.get('im_livechat.channel').get_info_for_chat_src(cr, uid, channel)
|
||||
info["script"] = script
|
||||
return request.make_response(env.get_template("web_page.html").render(info),
|
||||
headers=[('Content-Type', "text/html")])
|
||||
|
||||
@http.route('/im_livechat/available', type='json')
|
||||
@http.route('/im_livechat/available', type='json', auth="none")
|
||||
def available(self, db, channel):
|
||||
request.session.authenticate(db=db, login="anonymous", password="anonymous")
|
||||
return request.session.model('im_livechat.channel').get_available_user(channel) > 0
|
||||
reg, uid = self._auth(db)
|
||||
with reg.cursor() as cr:
|
||||
return reg.get('im_livechat.channel').get_available_user(cr, uid, channel) > 0
|
||||
|
||||
class im_livechat_channel(osv.osv):
|
||||
_name = 'im_livechat.channel'
|
||||
|
|
|
@ -135,11 +135,47 @@
|
|||
<record model="account.account.template" id="a189">
|
||||
<field name="name">Tax Receivable</field>
|
||||
<field name="code">189</field>
|
||||
<field name="type">other</field>
|
||||
<field name="type">view</field>
|
||||
<field name="user_type" ref="account.data_account_type_asset"/>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="parent_id" ref="a10"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="a189100">
|
||||
<field name="name">Purchase Tax Receivable</field>
|
||||
<field name="code">189100</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="a189"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="a189200">
|
||||
<field name="name">VAT Receivable</field>
|
||||
<field name="code">189200</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="a189"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="a189300">
|
||||
<field name="name">Service Tax Receivable</field>
|
||||
<field name="code">189300</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="a189"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="a189400">
|
||||
<field name="name">Exice Duty Receivable</field>
|
||||
<field name="code">189400</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="reconcile" eval="True"/>
|
||||
<field name="parent_id" ref="a189"/>
|
||||
</record>
|
||||
|
||||
<!-- Liabilities -->
|
||||
|
||||
<record model="account.account.template" id="a20">
|
||||
|
|
|
@ -2,269 +2,403 @@
|
|||
<openerp>
|
||||
<data noupdate="1">
|
||||
<!-- Taxes Sale Tax -->
|
||||
|
||||
|
||||
<record id="sales_private" model="account.tax.template">
|
||||
<field name="name">Sale Tax-15%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
<field name="name">Sales Tax 15%</field>
|
||||
<field name="description">Sales Tax 15%</field>
|
||||
<field name="amount">0.15</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2161"/>
|
||||
<field name="account_paid_id" ref="a2161"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="account_paid_id" ref="a2161"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale15"/>
|
||||
<field name="tax_code_id" ref="vat_code_rec_sale15"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale15"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_rec_sale15"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="sales_private_main" model="account.tax.template">
|
||||
<field name="name">Sale Tax-12%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
<field name="name">Sales Tax 12%</field>
|
||||
<field name="description">Sales Tax 12%</field>
|
||||
<field name="amount">0.12</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2161"/>
|
||||
<field name="account_paid_id" ref="a2161"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="account_paid_id" ref="a2161"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale12"/>
|
||||
<field name="tax_code_id" ref="vat_code_rec_sale12"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale12"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_rec_sale12"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="sales_private_main_4" model="account.tax.template">
|
||||
<field name="name">Sale Tax-4%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
<field name="name">Sales Tax 4%</field>
|
||||
<field name="description">Sales Tax 4%</field>
|
||||
<field name="amount">0.04</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2161"/>
|
||||
<field name="account_paid_id" ref="a2161"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale4"/>
|
||||
<field name="tax_code_id" ref="vat_code_rec_sale4"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale4"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_rec_sale4"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<!-- Purchase tax -->
|
||||
|
||||
|
||||
<record id="purchase_tax_private" model="account.tax.template">
|
||||
<field name="name">Purchase Tax-15%</field>
|
||||
<field name="name">Purchase Tax 15%</field>
|
||||
<field name="description">Purchase Tax 15%</field>
|
||||
<field name="account_collected_id" ref="a189"/>
|
||||
<field name="account_paid_id" ref="a189"/>
|
||||
<field name="price_include" eval="0"/>
|
||||
<field name="account_paid_id" ref="a189"/>
|
||||
<field name="amount">0.15</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_purchase"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_purchase"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_pur15"/>
|
||||
<field name="tax_code_id" ref="vat_code_pay_pur4"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_pur15"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_pay_pur4"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- vat -->
|
||||
|
||||
<record id="vat_private_main" model="account.tax.template">
|
||||
<field name="name">VAT-5%(4% VAT+1% Add. Tax.)</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
|
||||
<record id="vat_private_out_vat5" model="account.tax.template">
|
||||
<field name="name">Output VAT 5% (VAT 4% + Add. VAT 1%)</field>
|
||||
<field name="description">Output VAT 5%</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.04</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sal_vat5"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_vat5"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sal_vat5"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_vat5"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_in_vat5" model="account.tax.template">
|
||||
<field name="name">Input VAT 5% (VAT 4% + Add. VAT 1%)</field>
|
||||
<field name="description">Input VAT 5%</field>
|
||||
<field name="amount">0.05</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="base_sign">1</field>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="tax_sign">1</field>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_base_sign">1</field>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_tax_sign">1</field>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="a189200"/>
|
||||
<field name="account_paid_id" ref="a189200"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_vat5"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_vat5"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_vat5"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_vat5"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_main_tax" model="account.tax.template">
|
||||
<field name="name">VAT-15%(12.5% VAT+2.5% Add. Tax.)</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
|
||||
<record id="vat_private_in_vat15" model="account.tax.template">
|
||||
<field name="name">Input VAT 15% (VAT 12.5% + Add. VAT 2.5%)</field>
|
||||
<field name="description">Input VAT 15%</field>
|
||||
<field name="amount">0.15</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="base_sign">1</field>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="tax_sign">1</field>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_base_sign">1</field>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_tax_sign">1</field>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="a189200"/>
|
||||
<field name="account_paid_id" ref="a189200"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_vat15"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_vat15"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_vat15"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_vat15"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_tax" model="account.tax.template">
|
||||
<field name="name">VAT-8%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
|
||||
<record id="vat_private_out_vat15" model="account.tax.template">
|
||||
<field name="name">Output VAT 15% (VAT 12.5% + Add. VAT 2.5%)</field>
|
||||
<field name="description">Output VAT 15%</field>
|
||||
<field name="amount">0.15</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sal_vat15"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_vat15"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sal_vat15"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_vat15"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_in_vat8" model="account.tax.template">
|
||||
<field name="name">Input VAT 8%</field>
|
||||
<field name="description">Input VAT 8%</field>
|
||||
<field name="amount">0.08</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="a189200"/>
|
||||
<field name="account_paid_id" ref="a189200"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_vat8"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_vat8"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_vat8"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_vat8"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_tax_10" model="account.tax.template">
|
||||
<field name="name">VAT-10%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
<record id="vat_private_out_vat8" model="account.tax.template">
|
||||
<field name="name">Output VAT 8%</field>
|
||||
<field name="description">Output VAT 8%</field>
|
||||
<field name="amount">0.08</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sal_vat8"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_vat8"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sal_vat8"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_vat8"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_in_vat10" model="account.tax.template">
|
||||
<field name="name">Input VAT 10%</field>
|
||||
<field name="description">Input VAT 10%</field>
|
||||
<field name="amount">0.10</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="a189200"/>
|
||||
<field name="account_paid_id" ref="a189200"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_vat10"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_vat10"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_vat10"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_vat10"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_tax_12" model="account.tax.template">
|
||||
<field name="name">VAT-12.5%</field>
|
||||
<field name="price_include" eval="0"/>
|
||||
<field name="amount">12.5</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<!-- Exice Duty -->
|
||||
|
||||
<record id="exice_duty_private_main" model="account.tax.template">
|
||||
<field name="name">Excise Duty-10.30%</field>
|
||||
<field name="include_base_amount" eval="True"/>
|
||||
<record id="vat_private_out_vat10" model="account.tax.template">
|
||||
<field name="name">Output VAT 10%</field>
|
||||
<field name="description">Output VAT 10%</field>
|
||||
<field name="amount">0.10</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="a2164"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="base_sign">1</field>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="tax_sign">1</field>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_base_sign">1</field>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_tax_sign">1</field>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sal_vat10"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_vat10"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sal_vat10"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_vat10"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="exice_private_duty_parent" model="account.tax.template">
|
||||
<field name="name">Excise Duty-2%</field>
|
||||
<field name="amount">0.02</field>
|
||||
|
||||
<record id="vat_private_in_vat12" model="account.tax.template">
|
||||
<field name="name">Input VAT 12.5%</field>
|
||||
<field name="description">Input VAT 12.5%</field>
|
||||
<field name="amount">0.125</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="a189200"/>
|
||||
<field name="account_paid_id" ref="a189200"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_vat12"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_vat12"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_vat12"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_vat12"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="vat_private_out_vat12" model="account.tax.template">
|
||||
<field name="name">Output VAT 12.5%</field>
|
||||
<field name="description">Output VAT 12.5%</field>
|
||||
<field name="amount">0.125</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="parent_id" ref="exice_duty_private_main"/>
|
||||
<field name="account_collected_id" ref="a2164"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="base_sign">1</field>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="tax_sign">1</field>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_base_sign">1</field>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_tax_sign">1</field>
|
||||
<field name="account_collected_id" ref="a2162"/>
|
||||
<field name="account_paid_id" ref="a2162"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sal_vat12"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_vat12"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sal_vat12"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_vat12"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="exice_private_duty" model="account.tax.template">
|
||||
<field name="name">Excise Duty-1%</field>
|
||||
<field name="amount">0.01</field>
|
||||
<field name="type">percent</field>
|
||||
|
||||
<!-- Exice Duty -->
|
||||
|
||||
<record id="exice_duty_private_sale12" model="account.tax.template">
|
||||
<field name="name">Excise Duty 12% - Sales</field>
|
||||
<field name="description">Excise Duty 12% - Sales</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.1200</field>
|
||||
<field name="account_collected_id" ref="a2164"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="base_sign">1</field>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="tax_sign">1</field>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_base_sign">1</field>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_tax_sign">1</field>
|
||||
<field name="parent_id" ref="exice_duty_private_main"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_exice12"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_exice12"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="exice_duty_private_sale2" model="account.tax.template">
|
||||
<field name="name">Excise Duty 2% - Sales</field>
|
||||
<field name="description">Excise Duty 2% - Sales</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.020</field>
|
||||
<field name="account_collected_id" ref="a2164"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_exice2"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_exice2"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="exice_duty_private_sale1" model="account.tax.template">
|
||||
<field name="name">Output Excise Duty 1%</field>
|
||||
<field name="description">Output Excise Duty 1%</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.0100</field>
|
||||
<field name="account_collected_id" ref="a2164"/>
|
||||
<field name="account_paid_id" ref="a2164"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_exice1"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sales_excise"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_exice1"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<!-- Service Tax -->
|
||||
|
||||
<record id="service_private_main" model="account.tax.template">
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="name">Service Tax-12.30%</field>
|
||||
<field name="include_base_amount" eval="True"/>
|
||||
|
||||
<record id="service_private_ser12_sale" model="account.tax.template">
|
||||
<field name="name">Output Service Tax 12%</field>
|
||||
<field name="description">Output Service Tax 12%</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.12</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="account_collected_id" ref="a2163"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="child_depend" eval="0"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_sale_ser12"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_st12"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_sale_ser12"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_st12"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="service_private_tax_parent" model="account.tax.template">
|
||||
<field name="name">Service Tax-%2</field>
|
||||
|
||||
<record id="service_private_ser2_sale" model="account.tax.template">
|
||||
<field name="name">Output Sales Service Tax 2%</field>
|
||||
<field name="description">Output Sales Service Tax 2%</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.02</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="sequence">3</field>
|
||||
<field name="account_collected_id" ref="a2163"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="parent_id" ref="service_private_main"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_st2"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_st2"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="parent_id" ref="service_private_ser12_sale"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="service_private_tax" model="account.tax.template">
|
||||
<field name="name">Service Tax-%1</field>
|
||||
|
||||
<record id="service_private_ser1_sale" model="account.tax.template">
|
||||
<field name="name">Output Service Tax 1%</field>
|
||||
<field name="description">Output Service Tax 1%</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.01</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="type_tax_use">all</field>
|
||||
<field name="sequence">5</field>
|
||||
<field name="account_collected_id" ref="a2163"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_base_tax_sale"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec"/>
|
||||
<field name="parent_id" ref="service_private_main"/>
|
||||
<field name="account_paid_id" ref="a2163"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_rec_st1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_rec_st1"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="parent_id" ref="service_private_ser12_sale"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="service_private_ser12_purchase" model="account.tax.template">
|
||||
<field name="name">Input Service Tax 12%</field>
|
||||
<field name="description">Input Service Tax 12%</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.1200</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="account_collected_id" ref="a189300"/>
|
||||
<field name="account_paid_id" ref="a189300"/>
|
||||
<field name="base_code_id" ref="vat_code_tax_pur_ser12"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_ic_st"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_tax_pur_ser12"/>
|
||||
<field name="ref_base_sign" eval="-1"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_ic_st"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="service_private_ser2_purchase" model="account.tax.template">
|
||||
<field name="name">Input Service Tax Edu. Cess. 2%</field>
|
||||
<field name="description">Input Service Tax Edu. Cess. 2%</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.0200</field>
|
||||
<field name="sequence">3</field>
|
||||
<field name="account_collected_id" ref="a189300"/>
|
||||
<field name="account_paid_id" ref="a189300"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_ic_edu_cess"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pur_PCST5"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="parent_id" ref="service_private_ser12_purchase"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
<record id="service_private_ser1_purchase" model="account.tax.template">
|
||||
<field name="name">Input Service Tax Seco. & HEC 1%</field>
|
||||
<field name="description">Input Service Tax Seco. & HEC 1%</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="type">percent</field>
|
||||
<field name="amount">0.0100</field>
|
||||
<field name="sequence">5</field>
|
||||
<field name="account_collected_id" ref="a189300"/>
|
||||
<field name="account_paid_id" ref="a189300"/>
|
||||
<field name="tax_code_id" ref="vat_code_tax_pay_ic_seco_hec"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_tax_pay_ic_seco_hec"/>
|
||||
<field name="ref_tax_sign" eval="-1"/>
|
||||
<field name="parent_id" ref="service_private_ser12_purchase"/>
|
||||
<field name="chart_template_id" ref="indian_chart_template_private"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -116,7 +116,7 @@
|
|||
<record model="account.account.template" id="p15400">
|
||||
<field name="name">Tax Receivable</field>
|
||||
<field name="code">15400</field>
|
||||
<field name="type">other</field>
|
||||
<field name="type">view</field>
|
||||
<field name="user_type" ref="account.data_account_type_asset"/>
|
||||
<field name="reconcile" eval="False"/>
|
||||
<field name="parent_id" ref="p10000"/>
|
||||
|
@ -658,7 +658,327 @@
|
|||
<field name="reconcile" eval="False"/>
|
||||
<field name="parent_id" ref="p96000"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="account.account.template" id="p154001">
|
||||
<field name="name">Input CST 5%</field>
|
||||
<field name="code">154001</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_expense"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154002">
|
||||
<field name="name">Input Service Tax Seco. & HEC 1%</field>
|
||||
<field name="code">154002</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154003">
|
||||
<field name="name">Input Credit - URD</field>
|
||||
<field name="code">154003</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154004">
|
||||
<field name="name">TDS on Audit Fees - 94J</field>
|
||||
<field name="code">154004</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154005">
|
||||
<field name="name">TDS on Commission Or Brokerage - 94H</field>
|
||||
<field name="code">154005</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154006">
|
||||
<field name="name">Input Credit - Import Duty</field>
|
||||
<field name="code">154006</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154007">
|
||||
<field name="name">Additional Duty (Imports) 4%</field>
|
||||
<field name="code">154007</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154008">
|
||||
<field name="name">Input Service Tax 12%</field>
|
||||
<field name="code">154008</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154009">
|
||||
<field name="name">Input Service Tax Edu. Cess. 2%</field>
|
||||
<field name="code">154009</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154010">
|
||||
<field name="name">TDS on Salary - 92B</field>
|
||||
<field name="code">154010</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154011">
|
||||
<field name="name">Input Excise Duty 6%</field>
|
||||
<field name="code">154011</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154012">
|
||||
<field name="name">Input Excise Duty 5%</field>
|
||||
<field name="code">154012</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154013">
|
||||
<field name="name">Input Excise Duty 12%</field>
|
||||
<field name="code">154013</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154014">
|
||||
<field name="name">Education Cess 2% - Purchase</field>
|
||||
<field name="code">154014</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154015">
|
||||
<field name="name">Seco. & Higher Edu. Cess 1% - Purchase</field>
|
||||
<field name="code">154015</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247001">
|
||||
<field name="name">Excise Duty 12% - Sales</field>
|
||||
<field name="code">247001</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247010">
|
||||
<field name="name">Education Cess 2% - Sales</field>
|
||||
<field name="code">247010</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247002">
|
||||
<field name="name">Seco. & Higher Edu. Cess 1% - Sales</field>
|
||||
<field name="code">247002</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154016">
|
||||
<field name="name">Input Sec. & HEC - Capital Goods</field>
|
||||
<field name="code">154016</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154017">
|
||||
<field name="name">TDS on Contractor - 94C</field>
|
||||
<field name="code">154017</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154018">
|
||||
<field name="name">TDS on Director's Interest</field>
|
||||
<field name="code">154018</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154019">
|
||||
<field name="name">TDS on Director's Remuneration - 92B</field>
|
||||
<field name="code">154019</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154020">
|
||||
<field name="name">TDS on Interest</field>
|
||||
<field name="code">154020</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154021">
|
||||
<field name="name">TDS on Professional Fees - 94J</field>
|
||||
<field name="code">154021</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154022">
|
||||
<field name="name">TDS on Rent - 94I</field>
|
||||
<field name="code">154022</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154023">
|
||||
<field name="name">Input Edu. Cess - Capital Goods</field>
|
||||
<field name="code">154023</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154024">
|
||||
<field name="name">Input Excise Duty 12% - Capital Goods</field>
|
||||
<field name="code">154024</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154025">
|
||||
<field name="name">Input VAT 4%</field>
|
||||
<field name="code">154025</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154026">
|
||||
<field name="name">Input Additional VAT 1%</field>
|
||||
<field name="code">154026</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154027">
|
||||
<field name="name">Input VAT 15%</field>
|
||||
<field name="code">154027</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247003">
|
||||
<field name="name">Output VAT 4%</field>
|
||||
<field name="code">247003</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247004">
|
||||
<field name="name">Output Adi. VAT 1%</field>
|
||||
<field name="code">247004</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247005">
|
||||
<field name="name">CST 2% on Sales - Against Form - C</field>
|
||||
<field name="code">247005</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247006">
|
||||
<field name="name">CST 5% on Sales</field>
|
||||
<field name="code">247006</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154028">
|
||||
<field name="name">Input VAT 12.5%</field>
|
||||
<field name="code">154028</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154029">
|
||||
<field name="name">Input Additional VAT 2.5%</field>
|
||||
<field name="code">154029</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p154030">
|
||||
<field name="name">Input CST 2%</field>
|
||||
<field name="code">154030</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_expense"/>
|
||||
<field name="parent_id" ref="p15400"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247007">
|
||||
<field name="name">CST 2% on Sales - CT3 Against Form C</field>
|
||||
<field name="code">247007</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247008">
|
||||
<field name="name">Output VAT 4% on Sales - CT3</field>
|
||||
<field name="code">247008</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record model="account.account.template" id="p247009">
|
||||
<field name="name">Output Adi. VAT 1% Sales CT3</field>
|
||||
<field name="code">247009</field>
|
||||
<field name="type">other</field>
|
||||
<field name="user_type" ref="account.data_account_type_liability"/>
|
||||
<field name="parent_id" ref="p24700"/>
|
||||
</record>
|
||||
|
||||
<record id="indian_chart_template_public" model="account.chart.template">
|
||||
<field name="name">India - Chart of Accounts for Public Ltd</field>
|
||||
<field name="account_root_id" ref="p0"/>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,6 +19,7 @@
|
|||
|
||||
<record model="account.tax.code.template" id="vat_code_payable">
|
||||
<field name="name">Tax Paid</field>
|
||||
<field name="sign">-1</field>
|
||||
<field name="parent_id" ref="vat_code_balance_net"/>
|
||||
</record>
|
||||
|
||||
|
@ -27,16 +28,540 @@
|
|||
<field name="parent_id" ref="vat_code_tax"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_sale">
|
||||
<field name="name">Base of Taxed Sales</field>
|
||||
<field name="name">Taxable Sale Bases</field>
|
||||
<field name="parent_id" ref="vat_code_base_net"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_purchase">
|
||||
<field name="name">Base of Taxed Purchases</field>
|
||||
<field name="name">Taxable Purchase Bases</field>
|
||||
<field name="parent_id" ref="vat_code_base_net"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_CSTP5">
|
||||
<field name="name">Input CST 5%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_PCST5">
|
||||
<field name="name">Purchase CST 5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_ser12">
|
||||
<field name="name">Purchase Service Tax 12%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sale_ser12">
|
||||
<field name="name">Sales Service Tax 12%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_exice_salebase">
|
||||
<field name="name">Excise Duty 12.36% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_exice12">
|
||||
<field name="name">Excise Duty 12% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_exice_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_exice2">
|
||||
<field name="name">Excise Duty 2% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_exice1">
|
||||
<field name="name">Excise Duty 1% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_ic_st_purbase">
|
||||
<field name="name">Excise Duty 12.36% - Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_exice12">
|
||||
<field name="name">Excise Duty 12% - Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_purbase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_cess2">
|
||||
<field name="name">Education Cess 2% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_exice_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_cess2">
|
||||
<field name="name">Education Cess 2% - Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_purbase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_import_duty">
|
||||
<field name="name">Input Credit - Import Duty</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_edu_cess">
|
||||
<field name="name">Input Credit On Capital Goods - Edu. Cess</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_cap_goods">
|
||||
<field name="name">Input Excise Duty 12% - Capital Goods</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_seco_hec">
|
||||
<field name="name">Input Credit on Capital Goods - Seco. & HEC</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_ic_st_base">
|
||||
<field name="name">Input Service Tax 12.36%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_ic_st">
|
||||
<field name="name">Input Service Tax 12%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_base"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_ic_edu_cess">
|
||||
<field name="name">Input Service Tax Edu. Cess. 2%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_base"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_ic_seco_hec">
|
||||
<field name="name">Input Service Tax Seco. & HEC 1%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_base"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_sec_hig_edu">
|
||||
<field name="name">Seco. & Higher Edu. Cess 1% - Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_tax_pay_ic_st_purbase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_sec_hig_cess">
|
||||
<field name="name">Seco. & Higher Edu. Cess 1% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_exice_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_cst2">
|
||||
<field name="name">CST 2% on Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_cst5">
|
||||
<field name="name">CST 5% on Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_add_vat1">
|
||||
<field name="name">Input Additional VAT 1%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_add_vat2">
|
||||
<field name="name">Input Additional Vat 2.5%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat12">
|
||||
<field name="name">Input VAT 12.5%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat15">
|
||||
<field name="name">Input VAT 15%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat10">
|
||||
<field name="name">Input VAT 10%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat8">
|
||||
<field name="name">Input VAT 8%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat5">
|
||||
<field name="name">Input VAT 5%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_vat4">
|
||||
<field name="name">Input VAT 4%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat15">
|
||||
<field name="name">Output VAT 15%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat12">
|
||||
<field name="name">Output VAT 12.5%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat10">
|
||||
<field name="name">Output VAT 10%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat8">
|
||||
<field name="name">Output VAT 8%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat5">
|
||||
<field name="name">Output VAT 5%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_vat4">
|
||||
<field name="name">Output VAT 4%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_add_vat1">
|
||||
<field name="name">Output Adi. VAT 1%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_cst2">
|
||||
<field name="name">CST 2% on Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_exice5">
|
||||
<field name="name">Input Excise Duty 5%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_exice6">
|
||||
<field name="name">Input Excise Duty 6%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_urd">
|
||||
<field name="name">Input Credit - URD</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_audit_fee">
|
||||
<field name="name">TDS on Audit Fees - 94J</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_brokerage">
|
||||
<field name="name">TDS on Commission Or Brokerage- 94H</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_contractor">
|
||||
<field name="name">TDS on Contractor-94C</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_dir_intrest">
|
||||
<field name="name">TDS on Director's Interest</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_dir_ren">
|
||||
<field name="name">TDS on Director's Remuneration - 92B</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_intrest">
|
||||
<field name="name">TDS on Interest</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_prof_fee">
|
||||
<field name="name">TDS on Professional Fees - 94J</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_rent">
|
||||
<field name="name">TDS on Rent - 94I</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_tds_sal">
|
||||
<field name="name">TDS on Salary - 92B</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_tds_pur_import">
|
||||
<field name="name">Import Purchase</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat">
|
||||
<field name="name">Purchase VAT 4% / VAT 12.5% / VAT 15% / CST 2% / CST 5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_plant_machinery">
|
||||
<field name="name">Plant & Machinery</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_exp_act">
|
||||
<field name="name">Expense Accounts</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sales_excise">
|
||||
<field name="name">Sales Excise</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sale_cst2">
|
||||
<field name="name">Sales CST 2%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sale_cst15">
|
||||
<field name="name">Sales CST 5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat15">
|
||||
<field name="name">Purchase VAT 15%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat12">
|
||||
<field name="name">Purchase VAT 12.5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat10">
|
||||
<field name="name">Purchase VAT 10%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat8">
|
||||
<field name="name">Purchase VAT 8%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat5">
|
||||
<field name="name">Purchase VAT 5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat4">
|
||||
<field name="name">Purchase VAT 4%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_vat25">
|
||||
<field name="name">Purchase VAT 2.5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat15">
|
||||
<field name="name">Sales VAT 15%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat12">
|
||||
<field name="name">Sales VAT 12.5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat10">
|
||||
<field name="name">Sales VAT 10%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat8">
|
||||
<field name="name">Sales VAT 8%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat5">
|
||||
<field name="name">Sales VAT 5%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_vat4">
|
||||
<field name="name">Sales VAT 4%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_cst2">
|
||||
<field name="name">Input CST 2%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_urd">
|
||||
<field name="name">Purchase URD</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pur_base_tds">
|
||||
<field name="name">Base Expenses for TDS</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_pay_add_imp_duty">
|
||||
<field name="name">Additional Duty (Imports) 4%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_formh_tax">
|
||||
<field name="name">Sales Export - Form H - With Tax</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_cst2_on_sal_cst3">
|
||||
<field name="name">CST 2% on Sales CT3</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_cst3">
|
||||
<field name="name">Sales CT3 VAT</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_out4_sal_cst3">
|
||||
<field name="name">Output VAT 4% on Sales CT3</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_out_add1_sale_cst3">
|
||||
<field name="name">Output Adi. VAT 1% on Sales CT3</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_ct3_cst">
|
||||
<field name="name">Sales CT3 CST</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_exp_ct1">
|
||||
<field name="name">Sales Export - Form H - With CT1</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_sez_out_guj">
|
||||
<field name="name">Sales Export - SEZ - Out of Gujarat</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_sez_in_guj">
|
||||
<field name="name">Sales Export - SEZ - In Gujarat</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_no_saz_ogs">
|
||||
<field name="name">No Tax SEZ OGS</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_no_sez_guj">
|
||||
<field name="name">No Tax SEZ Gujarat</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_out_country">
|
||||
<field name="name">Sales Export - Out of Country</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_sal_proj">
|
||||
<field name="name">Sales Others (Projects)</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_formh_bed">
|
||||
<field name="name">No Tax Form H with BED</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_fomh">
|
||||
<field name="name">No Tax Form H</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_no_out_country">
|
||||
<field name="name">No Tax Export Out of Country</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_no_proj">
|
||||
<field name="name">No Tax Projects</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_st_salebase">
|
||||
<field name="name">Service Tax 12.36% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_st12">
|
||||
<field name="name">Service Tax 12% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_st_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_st2">
|
||||
<field name="name">Service Tax 2% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_st_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_tax_rec_st1">
|
||||
<field name="name">Service Tax 1% - Sales</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec_st_salebase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_sale15">
|
||||
<field name="name">Sales Tax 15%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_rec_sale15">
|
||||
<field name="name">Sales Tax - 15%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_sale12">
|
||||
<field name="name">Sales Tax 12%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_rec_sale12">
|
||||
<field name="name">Sales Tax - 12%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_sale4">
|
||||
<field name="name">Sales Tax 4%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_sale"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_rec_sale4">
|
||||
<field name="name">Sales Tax - 4%</field>
|
||||
<field name="parent_id" ref="vat_code_tax_rec"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_base_tax_pur15">
|
||||
<field name="name">Purchase Tax 15%</field>
|
||||
<field name="parent_id" ref="vat_code_base_tax_purchase"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.code.template" id="vat_code_pay_pur4">
|
||||
<field name="name">Purchase Tax - 15%</field>
|
||||
<field name="parent_id" ref="vat_code_payable"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -21,7 +21,7 @@ email overload.
|
|||
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=mail" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -967,6 +967,24 @@ openerp.mail = function (session) {
|
|||
this.$('.oe_reply').on('click', this.on_message_reply);
|
||||
this.$('.oe_star').on('click', this.on_star);
|
||||
this.$('.oe_msg_vote').on('click', this.on_vote);
|
||||
this.$('.oe_mail_action_model').on('click', this.on_record_clicked);
|
||||
},
|
||||
|
||||
on_record_clicked: function (event) {
|
||||
event.stopPropagation();
|
||||
var state = {
|
||||
'model': this.model,
|
||||
'id': this.res_id,
|
||||
'title': this.record_name
|
||||
};
|
||||
session.webclient.action_manager.do_push_state(state);
|
||||
this.do_action({
|
||||
res_model: state.model,
|
||||
res_id: state.id,
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'form']]
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
/* Call the on_compose_message on the thread of this message. */
|
||||
|
|
|
@ -20,7 +20,7 @@ planning with the smart kanban and gantt views. Use the advanced analytics
|
|||
features to detect bottleneck in resources capacities and inventory locations.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=mrp" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
Organize yourself with efficient todo lists and notes. From personnal tasks to collaborative meeting minutes, increase your user's productivity by giving them the tools to prioritize their work, share their ideas and collaborate on documents.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=note" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="description" position="replace">
|
||||
<field name="description_pad" attrs="{'readonly':[('state','=','done')]}" widget="pad"/>
|
||||
<field name="description_pad" widget="pad"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -4,29 +4,31 @@ import simplejson
|
|||
import os
|
||||
import openerp
|
||||
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.web.controllers.main import manifest_list, module_boot, html_template
|
||||
|
||||
class PointOfSaleController(openerp.addons.web.http.Controller):
|
||||
_cp_path = '/pos'
|
||||
class PointOfSaleController(http.Controller):
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def app(self, req, s_action=None, **kw):
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list(req, None, 'js'))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list(req, None, 'css'))
|
||||
@http.route('/pos/app', type='http', auth='admin')
|
||||
def app(self):
|
||||
js = "\n ".join('<script type="text/javascript" src="%s"></script>' % i for i in manifest_list('js',db=request.db))
|
||||
css = "\n ".join('<link rel="stylesheet" href="%s">' % i for i in manifest_list('css',db=request.db))
|
||||
|
||||
cookie = req.httprequest.cookies.get("instance0|session_id")
|
||||
cookie = request.httprequest.cookies.get("instance0|session_id")
|
||||
session_id = cookie.replace("%22","")
|
||||
template = html_template.replace('<html','<html manifest="/pos/manifest?session_id=%s"'%session_id)
|
||||
template = html_template.replace('<html','<html manifest="/pos/manifest?session_id=%s"' % request.session_id)
|
||||
|
||||
r = template % {
|
||||
'js': js,
|
||||
'css': css,
|
||||
'modules': simplejson.dumps(module_boot(req)),
|
||||
'modules': simplejson.dumps(module_boot(request)),
|
||||
'init': 'var wc = new s.web.WebClient();wc.appendTo($(document.body));'
|
||||
}
|
||||
return r
|
||||
|
||||
@openerp.addons.web.http.httprequest
|
||||
def manifest(self, req, **kwargs):
|
||||
@http.route('/pos/manifest',type='http', auth='admin')
|
||||
def manifest(self):
|
||||
""" This generates a HTML5 cache manifest files that preloads the categories and products thumbnails
|
||||
and other ressources necessary for the point of sale to work offline """
|
||||
|
||||
|
@ -45,16 +47,16 @@ class PointOfSaleController(openerp.addons.web.http.Controller):
|
|||
imgdir = openerp.modules.get_module_resource('point_of_sale','static/src/img');
|
||||
load_css_img(imgdir,'/point_of_sale/static/src/img')
|
||||
|
||||
products = req.session.model('product.product')
|
||||
for p in products.search_read([('pos_categ_id','!=',False)], ['name']):
|
||||
products = request.registry.get('product.product')
|
||||
for p in products.search_read(request.cr, request.uid, [('pos_categ_id','!=',False)], ['name']):
|
||||
product_id = p['id']
|
||||
url = "/web/binary/image?session_id=%s&model=product.product&field=image&id=%s" % (req.session_id, product_id)
|
||||
url = "/web/binary/image?session_id=%s&model=product.product&field=image&id=%s" % (request.session_id, product_id)
|
||||
ml.append(url)
|
||||
|
||||
categories = req.session.model('pos.category')
|
||||
for c in categories.search_read([],['name']):
|
||||
categories = request.registry.get('pos.category')
|
||||
for c in categories.search_read(request.cr, request.uid, [], ['name']):
|
||||
category_id = c['id']
|
||||
url = "/web/binary/image?session_id=%s&model=pos.category&field=image&id=%s" % (req.session_id, category_id)
|
||||
url = "/web/binary/image?session_id=%s&model=pos.category&field=image&id=%s" % (request.session_id, category_id)
|
||||
ml.append(url)
|
||||
|
||||
ml += ["NETWORK:","*"]
|
||||
|
@ -62,108 +64,103 @@ class PointOfSaleController(openerp.addons.web.http.Controller):
|
|||
|
||||
return m
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def dispatch(self, request, iface, **kwargs):
|
||||
method = 'iface_%s' % iface
|
||||
return getattr(self, method)(request, **kwargs)
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def scan_item_success(self, request, ean):
|
||||
@http.route('/pos/scan_item_success', type='json', auth='admin')
|
||||
def scan_item_success(self, ean):
|
||||
"""
|
||||
A product has been scanned with success
|
||||
"""
|
||||
print 'scan_item_success: ' + str(ean)
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def scan_item_error_unrecognized(self, request, ean):
|
||||
@http.route('/pos/scan_item_error_unrecognized')
|
||||
def scan_item_error_unrecognized(self, ean):
|
||||
"""
|
||||
A product has been scanned without success
|
||||
"""
|
||||
print 'scan_item_error_unrecognized: ' + str(ean)
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def help_needed(self, request):
|
||||
@http.route('/pos/help_needed', type='json', auth='admin')
|
||||
def help_needed(self):
|
||||
"""
|
||||
The user wants an help (ex: light is on)
|
||||
"""
|
||||
print "help_needed"
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def help_canceled(self, request):
|
||||
@http.route('/pos/help_canceled', type='json', auth='admin')
|
||||
def help_canceled(self):
|
||||
"""
|
||||
The user stops the help request
|
||||
"""
|
||||
print "help_canceled"
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def weighting_start(self, request):
|
||||
@http.route('/pos/weighting_start', type='json', auth='admin')
|
||||
def weighting_start(self):
|
||||
print "weighting_start"
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def weighting_read_kg(self, request):
|
||||
@http.route('/pos/weighting_read_kg', type='json', auth='admin')
|
||||
def weighting_read_kg(self):
|
||||
print "weighting_read_kg"
|
||||
return 0.0
|
||||
return 3.14
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def weighting_end(self, request):
|
||||
@http.route('/pos/weighting_end', type='json', auth='admin')
|
||||
def weighting_end(self):
|
||||
print "weighting_end"
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def payment_request(self, request, price):
|
||||
@http.route('/pos/payment_request', type='json', auth='admin')
|
||||
def payment_request(self, price):
|
||||
"""
|
||||
The PoS will activate the method payment
|
||||
"""
|
||||
print "payment_request: price:"+str(price)
|
||||
return 'ok'
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def payment_status(self, request):
|
||||
@http.route('/pos/payment_status', type='json', auth='admin')
|
||||
def payment_status(self):
|
||||
print "payment_status"
|
||||
return { 'status':'waiting' }
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def payment_cancel(self, request):
|
||||
@http.route('/pos/payment_cancel', type='json', auth='admin')
|
||||
def payment_cancel(self):
|
||||
print "payment_cancel"
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def transaction_start(self, request):
|
||||
@http.route('/pos/transaction_start', type='json', auth='admin')
|
||||
def transaction_start(self):
|
||||
print 'transaction_start'
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def transaction_end(self, request):
|
||||
@http.route('/pos/transaction_end', type='json', auth='admin')
|
||||
def transaction_end(self):
|
||||
print 'transaction_end'
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def cashier_mode_activated(self, request):
|
||||
@http.route('/pos/cashier_mode_activated', type='json', auth='admin')
|
||||
def cashier_mode_activated(self):
|
||||
print 'cashier_mode_activated'
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def cashier_mode_deactivated(self, request):
|
||||
@http.route('/pos/cashier_mode_deactivated', type='json', auth='admin')
|
||||
def cashier_mode_deactivated(self):
|
||||
print 'cashier_mode_deactivated'
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def open_cashbox(self, request):
|
||||
@http.route('/pos/open_cashbox', type='json', auth='admin')
|
||||
def open_cashbox(self):
|
||||
print 'open_cashbox'
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def print_receipt(self, request, receipt):
|
||||
@http.route('/pos/print_receipt', type='json', auth='admin')
|
||||
def print_receipt(self, receipt):
|
||||
print 'print_receipt' + str(receipt)
|
||||
return
|
||||
|
||||
@openerp.addons.web.http.jsonrequest
|
||||
def print_pdf_invoice(self, request, pdfinvoice):
|
||||
@http.route('/pos/print_pdf_invoice', type='json', auth='admin')
|
||||
def print_pdf_invoice(self, pdfinvoice):
|
||||
print 'print_pdf_invoice' + str(pdfinvoice)
|
||||
return
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ class pos_config(osv.osv):
|
|||
'iface_electronic_scale' : fields.boolean('Electronic Scale Interface'),
|
||||
'iface_vkeyboard' : fields.boolean('Virtual KeyBoard Interface'),
|
||||
'iface_print_via_proxy' : fields.boolean('Print via Proxy'),
|
||||
'iface_invoicing': fields.boolean('Invoicing',help='Enables invoice generation from the Point of Sale'),
|
||||
|
||||
'state' : fields.selection(POS_CONFIG_STATE, 'Status', required=True, readonly=True),
|
||||
'sequence_id' : fields.many2one('ir.sequence', 'Order IDs Sequence', readonly=True,
|
||||
|
@ -127,7 +128,8 @@ class pos_config(osv.osv):
|
|||
'warehouse_id': _default_warehouse,
|
||||
'journal_id': _default_sale_journal,
|
||||
'group_by' : True,
|
||||
'pricelist_id': _default_pricelist
|
||||
'pricelist_id': _default_pricelist,
|
||||
'iface_invoicing': True,
|
||||
}
|
||||
|
||||
def set_active(self, cr, uid, ids, context=None):
|
||||
|
@ -492,13 +494,17 @@ class pos_order(osv.osv):
|
|||
#_logger.info("orders: %r", orders)
|
||||
order_ids = []
|
||||
for tmp_order in orders:
|
||||
to_invoice = tmp_order['to_invoice']
|
||||
order = tmp_order['data']
|
||||
|
||||
|
||||
order_id = self.create(cr, uid, {
|
||||
'name': order['name'],
|
||||
'user_id': order['user_id'] or False,
|
||||
'session_id': order['pos_session_id'],
|
||||
'lines': order['lines'],
|
||||
'pos_reference':order['name']
|
||||
'pos_reference':order['name'],
|
||||
'partner_id': order['partner_id'] or False
|
||||
}, context)
|
||||
|
||||
for payments in order['statement_ids']:
|
||||
|
@ -529,6 +535,12 @@ class pos_order(osv.osv):
|
|||
}, context=context)
|
||||
order_ids.append(order_id)
|
||||
self.signal_paid(cr, uid, [order_id])
|
||||
|
||||
if to_invoice:
|
||||
self.action_invoice(cr, uid, [order_id], context)
|
||||
order_obj = self.browse(cr, uid, order_id, context)
|
||||
self.pool['account.invoice'].signal_invoice_open(cr, uid, [order_obj.invoice_id.id])
|
||||
|
||||
return order_ids
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
|
@ -881,6 +893,7 @@ class pos_order(osv.osv):
|
|||
inv_line_ref.create(cr, uid, inv_line, context=context)
|
||||
inv_ref.button_reset_taxes(cr, uid, [inv_id], context=context)
|
||||
self.signal_invoice(cr, uid, [order.id])
|
||||
inv_ref.signal_validate(cr, uid, [inv_id])
|
||||
|
||||
if not inv_ids: return {}
|
||||
|
||||
|
|
|
@ -794,6 +794,7 @@
|
|||
<field name="iface_self_checkout" />
|
||||
<field name="iface_cashdrawer" />
|
||||
<field name="iface_payment_terminal" />
|
||||
<field name="iface_invoicing" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="iface_electronic_scale" />
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
consolidations amongst all shops without the hassle of integrating several applications.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=point_of_sale" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -291,10 +291,15 @@
|
|||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
width: 205px;
|
||||
max-height: 232px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.point-of-sale #paypad button {
|
||||
height: 50px;
|
||||
width: 208px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0px -6px 4px -2px;
|
||||
font-weight: bold;
|
||||
vertical-align: middle;
|
||||
|
@ -302,6 +307,17 @@
|
|||
border-top: 1px solid #efefef;
|
||||
font-size: 14px;
|
||||
}
|
||||
.point-of-sale #paypad button, .point-of-sale #numpad button, .point-of-sale .popup button{
|
||||
position: relative;
|
||||
top: 0;
|
||||
-webkit-transition: top 150ms linear;
|
||||
-moz-transition: top 150ms linear;
|
||||
-ms-transition: top 150ms linear;
|
||||
transition: top 150ms linear;
|
||||
}
|
||||
.point-of-sale #paypad button:active, .point-of-sale #numpad button:active, .point-of-sale .popup button:active{
|
||||
top:3px;
|
||||
}
|
||||
.point-of-sale #paypad button:hover, .point-of-sale #numpad button:hover, .point-of-sale #numpad .selected-mode, .point-of-sale .popup button:hover {
|
||||
border: none;
|
||||
color: white;
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
|
@ -267,11 +267,21 @@ function openerp_pos_db(instance, module){
|
|||
return results;
|
||||
},
|
||||
add_order: function(order){
|
||||
var last_id = this.load('last_order_id',0);
|
||||
var order_id = order.uid;
|
||||
var orders = this.load('orders',[]);
|
||||
orders.push({id: last_id + 1, data: order});
|
||||
this.save('last_order_id',last_id+1);
|
||||
|
||||
// if the order was already stored, we overwrite its data
|
||||
for(var i = 0, len = orders.length; i < len; i++){
|
||||
if(orders[i].id === order_id){
|
||||
orders[i].data = order;
|
||||
this.save('orders',orders);
|
||||
return order_id;
|
||||
}
|
||||
}
|
||||
|
||||
orders.push({id: order_id, data: order});
|
||||
this.save('orders',orders);
|
||||
return order_id;
|
||||
},
|
||||
remove_order: function(order_id){
|
||||
var orders = this.load('orders',[]);
|
||||
|
@ -283,5 +293,14 @@ function openerp_pos_db(instance, module){
|
|||
get_orders: function(){
|
||||
return this.load('orders',[]);
|
||||
},
|
||||
get_order: function(order_id){
|
||||
var orders = this.get_orders();
|
||||
for(var i = 0, len = orders.length; i < len; i++){
|
||||
if(orders[i].id === order_id){
|
||||
return orders[i];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -104,7 +104,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
|
||||
return self.fetch('res.currency',['symbol','position','rounding','accuracy'],[['id','=',self.get('company').currency_id[0]]]);
|
||||
}).then(function(currencies){
|
||||
console.log('Currency:',currencies[0]);
|
||||
self.set('currency',currencies[0]);
|
||||
|
||||
return self.fetch('product.uom', null, null);
|
||||
|
@ -145,7 +144,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
['name','journal_ids','warehouse_id','journal_id','pricelist_id',
|
||||
'iface_self_checkout', 'iface_led', 'iface_cashdrawer',
|
||||
'iface_payment_terminal', 'iface_electronic_scale', 'iface_barscan', 'iface_vkeyboard',
|
||||
'iface_print_via_proxy','iface_cashdrawer','state','sequence_id','session_ids'],
|
||||
'iface_print_via_proxy','iface_cashdrawer','iface_invoicing','state','sequence_id','session_ids'],
|
||||
[['id','=', self.get('pos_session').config_id[0]]]
|
||||
);
|
||||
}).then(function(configs){
|
||||
|
@ -156,6 +155,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
self.iface_vkeyboard = !!pos_config.iface_vkeyboard;
|
||||
self.iface_self_checkout = !!pos_config.iface_self_checkout;
|
||||
self.iface_cashdrawer = !!pos_config.iface_cashdrawer;
|
||||
self.iface_invoicing = !!pos_config.iface_invoicing;
|
||||
|
||||
return self.fetch('stock.warehouse',[],[['id','=',pos_config.warehouse_id[0]]]);
|
||||
}).then(function(shops){
|
||||
|
@ -240,12 +240,6 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
}
|
||||
},
|
||||
|
||||
// saves the order locally and try to send it to the backend. 'record' is a bizzarely defined JSON version of the Order
|
||||
push_order: function(record) {
|
||||
this.db.add_order(record);
|
||||
this.flush();
|
||||
},
|
||||
|
||||
//creates a new empty order and sets it as the current order
|
||||
add_new_order: function(){
|
||||
var order = new module.Order({pos:this});
|
||||
|
@ -253,45 +247,161 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
this.set('selectedOrder', order);
|
||||
},
|
||||
|
||||
// saves the order locally and try to send it to the backend.
|
||||
// it returns a deferred that succeeds after having tried to send the order and all the other pending orders.
|
||||
push_order: function(order) {
|
||||
var self = this;
|
||||
var order_id = this.db.add_order(order.export_as_JSON());
|
||||
var pushed = new $.Deferred();
|
||||
|
||||
this.set('nbr_pending_operations',self.db.get_orders().length);
|
||||
|
||||
this.flush_mutex.exec(function(){
|
||||
var flushed = self._flush_all_orders();
|
||||
|
||||
flushed.always(function(){
|
||||
pushed.resolve();
|
||||
});
|
||||
|
||||
return flushed;
|
||||
});
|
||||
return pushed;
|
||||
},
|
||||
|
||||
// saves the order locally and try to send it to the backend and make an invoice
|
||||
// returns a deferred that succeeds when the order has been posted and successfully generated
|
||||
// an invoice. This method can fail in various ways:
|
||||
// error-no-client: the order must have an associated partner_id. You can retry to make an invoice once
|
||||
// this error is solved
|
||||
// error-transfer: there was a connection error during the transfer. You can retry to make the invoice once
|
||||
// the network connection is up
|
||||
|
||||
push_and_invoice_order: function(order){
|
||||
var self = this;
|
||||
var invoiced = new $.Deferred();
|
||||
|
||||
if(!order.get_client()){
|
||||
invoiced.reject('error-no-client');
|
||||
return invoiced;
|
||||
}
|
||||
|
||||
var order_id = this.db.add_order(order.export_as_JSON());
|
||||
|
||||
this.set('nbr_pending_operations',self.db.get_orders().length);
|
||||
|
||||
this.flush_mutex.exec(function(){
|
||||
var done = new $.Deferred(); // holds the mutex
|
||||
|
||||
// send the order to the server
|
||||
// we have a 30 seconds timeout on this push.
|
||||
// FIXME: if the server takes more than 30 seconds to accept the order,
|
||||
// the client will believe it wasn't successfully sent, and very bad
|
||||
// things will happen as a duplicate will be sent next time
|
||||
// so we must make sure the server detects and ignores duplicated orders
|
||||
|
||||
var transfer = self._flush_order(order_id, {timeout:30000, to_invoice:true});
|
||||
|
||||
transfer.fail(function(){
|
||||
invoiced.reject('error-transfer');
|
||||
done.reject();
|
||||
});
|
||||
|
||||
// on success, get the order id generated by the server
|
||||
transfer.pipe(function(order_server_id){
|
||||
// generate the pdf and download it
|
||||
self.pos_widget.do_action('point_of_sale.pos_invoice_report',{additional_context:{
|
||||
active_ids:order_server_id,
|
||||
}});
|
||||
invoiced.resolve();
|
||||
done.resolve();
|
||||
});
|
||||
|
||||
return done;
|
||||
|
||||
});
|
||||
|
||||
return invoiced;
|
||||
},
|
||||
|
||||
// attemps to send all pending orders ( stored in the pos_db ) to the server,
|
||||
// and remove the successfully sent ones from the db once
|
||||
// it has been confirmed that they have been sent correctly.
|
||||
flush: function() {
|
||||
//TODO make the mutex work
|
||||
//this makes sure only one _int_flush is called at the same time
|
||||
/*
|
||||
return this.flush_mutex.exec(_.bind(function() {
|
||||
return this._flush(0);
|
||||
}, this));
|
||||
*/
|
||||
this._flush(0);
|
||||
var self = this;
|
||||
var flushed = new $.Deferred();
|
||||
|
||||
this.flush_mutex.exec(function(){
|
||||
var done = new $.Deferred();
|
||||
|
||||
self._flush_all_orders()
|
||||
.done( function(){ flushed.resolve();})
|
||||
.fail( function(){ flushed.reject(); })
|
||||
.always(function(){ done.resolve(); });
|
||||
|
||||
return done;
|
||||
});
|
||||
|
||||
return flushed;
|
||||
},
|
||||
// attempts to send an order of index 'index' in the list of order to send. The index
|
||||
// is used to skip orders that failed. do not call this method outside the mutex provided
|
||||
// by flush()
|
||||
_flush: function(index){
|
||||
|
||||
// attempts to send the locally stored order of id 'order_id'
|
||||
// the sending is asynchronous and can take some time to decide if it is successful or not
|
||||
// it is therefore important to only call this method from inside a mutex
|
||||
// this method returns a deferred indicating wether the sending was successful or not
|
||||
// there is a timeout parameter which is set to 2 seconds by default.
|
||||
_flush_order: function(order_id, options){
|
||||
var self = this;
|
||||
options = options || {};
|
||||
timeout = typeof options.timeout === 'number' ? options.timeout : 5000;
|
||||
|
||||
var order = this.db.get_order(order_id);
|
||||
order.to_invoice = options.to_invoice || false;
|
||||
|
||||
if(!order){
|
||||
// flushing a non existing order always fails
|
||||
return (new $.Deferred()).reject();
|
||||
}
|
||||
|
||||
// we try to send the order. shadow prevents a spinner if it takes too long. (unless we are sending an invoice,
|
||||
// then we want to notify the user that we are waiting on something )
|
||||
var rpc = (new instance.web.Model('pos.order')).call('create_from_ui',[[order]],undefined,{shadow: !options.to_invoice, timeout:timeout});
|
||||
|
||||
rpc.fail(function(unused,event){
|
||||
// prevent an error popup creation by the rpc failure
|
||||
// we want the failure to be silent as we send the orders in the background
|
||||
event.preventDefault();
|
||||
console.error('Failed to send order:',order);
|
||||
});
|
||||
|
||||
rpc.done(function(){
|
||||
self.db.remove_order(order_id);
|
||||
self.set('nbr_pending_operations',self.db.get_orders().length);
|
||||
});
|
||||
|
||||
return rpc;
|
||||
},
|
||||
|
||||
// attempts to send all the locally stored orders. As with _flush_order, it should only be
|
||||
// called from within a mutex.
|
||||
// this method returns a deferred that always succeeds when all orders have been tried to be sent,
|
||||
// even if none of them could actually be sent.
|
||||
_flush_all_orders: function(){
|
||||
var self = this;
|
||||
var orders = this.db.get_orders();
|
||||
self.set('nbr_pending_operations',orders.length);
|
||||
var tried_all = new $.Deferred();
|
||||
|
||||
var order = orders[index];
|
||||
if(!order){
|
||||
return;
|
||||
function rec_flush(index){
|
||||
if(index < orders.length){
|
||||
self._flush_order(orders[index].id).always(function(){
|
||||
rec_flush(index+1);
|
||||
})
|
||||
}else{
|
||||
tried_all.resolve();
|
||||
}
|
||||
}
|
||||
//try to push an order to the server
|
||||
// shadow : true is to prevent a spinner to appear in case of timeout
|
||||
(new instance.web.Model('pos.order')).call('create_from_ui',[[order]],undefined,{ shadow:true })
|
||||
.fail(function(unused, event){
|
||||
//don't show error popup if it fails
|
||||
event.preventDefault();
|
||||
console.error('Failed to send order:',order);
|
||||
self._flush(index+1);
|
||||
})
|
||||
.done(function(){
|
||||
//remove from db if success
|
||||
self.db.remove_order(order.id);
|
||||
self._flush(index);
|
||||
});
|
||||
rec_flush(0);
|
||||
|
||||
return tried_all;
|
||||
},
|
||||
|
||||
scan_product: function(parsed_ean){
|
||||
|
@ -590,11 +700,12 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
module.Order = Backbone.Model.extend({
|
||||
initialize: function(attributes){
|
||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
||||
this.uid = this.generateUniqueId();
|
||||
this.set({
|
||||
creationDate: new Date(),
|
||||
orderLines: new module.OrderlineCollection(),
|
||||
paymentLines: new module.PaymentlineCollection(),
|
||||
name: "Order " + this.generateUniqueId(),
|
||||
name: "Order " + this.uid,
|
||||
client: null,
|
||||
});
|
||||
this.pos = attributes.pos;
|
||||
|
@ -770,7 +881,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
currency: this.pos.get('currency'),
|
||||
};
|
||||
},
|
||||
exportAsJSON: function() {
|
||||
export_as_JSON: function() {
|
||||
var orderLines, paymentLines;
|
||||
orderLines = [];
|
||||
(this.get('orderLines')).each(_.bind( function(item) {
|
||||
|
@ -789,8 +900,9 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal
|
|||
lines: orderLines,
|
||||
statement_ids: paymentLines,
|
||||
pos_session_id: this.pos.get('pos_session').id,
|
||||
partner_id: this.pos.get('client') ? this.pos.get('client').id : undefined,
|
||||
partner_id: this.get_client() ? this.get_client().id : false,
|
||||
user_id: this.pos.get('cashier') ? this.pos.get('cashier').id : this.pos.get('user').id,
|
||||
uid: this.uid,
|
||||
};
|
||||
},
|
||||
getSelectedLine: function(){
|
||||
|
|
|
@ -434,6 +434,14 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
template:'ErrorNegativePricePopupWidget',
|
||||
});
|
||||
|
||||
module.ErrorNoClientPopupWidget = module.ErrorPopupWidget.extend({
|
||||
template: 'ErrorNoClientPopupWidget',
|
||||
});
|
||||
|
||||
module.ErrorInvoiceTransferPopupWidget = module.ErrorPopupWidget.extend({
|
||||
template: 'ErrorInvoiceTransferPopupWidget',
|
||||
});
|
||||
|
||||
module.ScaleInviteScreenWidget = module.ScreenWidget.extend({
|
||||
template:'ScaleInviteScreenWidget',
|
||||
|
||||
|
@ -452,7 +460,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
clearInterval(this.intervalID);
|
||||
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
|
||||
}
|
||||
},500);
|
||||
},100);
|
||||
|
||||
this.add_action_button({
|
||||
label: _t('Back'),
|
||||
|
@ -507,7 +515,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
self.weight = weight;
|
||||
self.renderElement();
|
||||
}
|
||||
},200);
|
||||
},100);
|
||||
},
|
||||
renderElement: function(){
|
||||
var self = this;
|
||||
|
@ -640,7 +648,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
var cashregister = selfCheckoutRegisters[0] || self.pos.get('cashRegisters').models[0];
|
||||
currentOrder.addPaymentLine(cashregister);
|
||||
self.pos.push_order(currentOrder.exportAsJSON())
|
||||
self.pos.push_order(currentOrder)
|
||||
currentOrder.destroy();
|
||||
self.pos.proxy.transaction_end();
|
||||
self.pos_widget.screen_selector.set_current_screen(self.next_screen);
|
||||
|
@ -808,19 +816,42 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
this._super();
|
||||
var self = this;
|
||||
|
||||
this.add_action_button({
|
||||
var print_button = this.add_action_button({
|
||||
label: _t('Print'),
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/printer.png',
|
||||
click: function(){ self.print(); },
|
||||
});
|
||||
|
||||
this.add_action_button({
|
||||
var finish_button = this.add_action_button({
|
||||
label: _t('Next Order'),
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-next.png',
|
||||
click: function() { self.finishOrder(); },
|
||||
});
|
||||
|
||||
window.print();
|
||||
|
||||
// THIS IS THE HACK OF THE CENTURY
|
||||
//
|
||||
// The problem is that in chrome the print() is asynchronous and doesn't
|
||||
// execute until all rpc are finished. So it conflicts with the rpc used
|
||||
// to send the orders to the backend, and the user is able to go to the next
|
||||
// screen before the printing dialog is opened. The problem is that what's
|
||||
// printed is whatever is in the page when the dialog is opened and not when it's called,
|
||||
// and so you end up printing the product list instead of the receipt...
|
||||
//
|
||||
// Fixing this would need a re-architecturing
|
||||
// of the code to postpone sending of orders after printing.
|
||||
//
|
||||
// But since the print dialog also blocks the other asynchronous calls, the
|
||||
// button enabling in the setTimeout() is blocked until the printing dialog is
|
||||
// closed. But the timeout has to be big enough or else it doesn't work
|
||||
// 2 seconds is the same as the default timeout for sending orders and so the dialog
|
||||
// should have appeared before the timeout... so yeah that's not ultra reliable.
|
||||
|
||||
finish_button.set_disabled(true);
|
||||
setTimeout(function(){
|
||||
finish_button.set_disabled(false);
|
||||
}, 2000);
|
||||
},
|
||||
print: function() {
|
||||
window.print();
|
||||
|
@ -870,15 +901,15 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
this.set_numpad_state(this.pos_widget.numpad.state);
|
||||
|
||||
this.back_button = this.add_action_button({
|
||||
this.add_action_button({
|
||||
label: _t('Back'),
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/go-previous.png',
|
||||
click: function(){
|
||||
self.pos_widget.screen_selector.set_current_screen(self.back_screen);
|
||||
},
|
||||
});
|
||||
|
||||
this.validate_button = this.add_action_button({
|
||||
|
||||
this.add_action_button({
|
||||
label: _t('Validate'),
|
||||
name: 'validation',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/validate.png',
|
||||
|
@ -886,6 +917,17 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
self.validateCurrentOrder();
|
||||
},
|
||||
});
|
||||
|
||||
if(this.pos.iface_invoicing){
|
||||
this.add_action_button({
|
||||
label: 'Invoice',
|
||||
name: 'invoice',
|
||||
icon: '/point_of_sale/static/src/img/icons/png48/invoice.png',
|
||||
click: function(){
|
||||
self.validateCurrentOrder({invoice: true});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
this.updatePaymentSummary();
|
||||
this.line_refocus();
|
||||
|
@ -898,15 +940,44 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
back: function() {
|
||||
this.pos_widget.screen_selector.set_current_screen(self.back_screen);
|
||||
},
|
||||
validateCurrentOrder: function() {
|
||||
validateCurrentOrder: function(options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
|
||||
var currentOrder = this.pos.get('selectedOrder');
|
||||
|
||||
this.pos.push_order(currentOrder.exportAsJSON())
|
||||
if(this.pos.iface_print_via_proxy){
|
||||
this.pos.proxy.print_receipt(currentOrder.export_for_printing());
|
||||
this.pos.get('selectedOrder').destroy(); //finish order and go back to scan screen
|
||||
|
||||
if(options.invoice){
|
||||
// deactivate the validation button while we try to send the order
|
||||
this.pos_widget.action_bar.set_button_disabled('validation',true);
|
||||
this.pos_widget.action_bar.set_button_disabled('invoice',true);
|
||||
|
||||
var invoiced = this.pos.push_and_invoice_order(currentOrder);
|
||||
|
||||
invoiced.fail(function(error){
|
||||
if(error === 'error-no-client'){
|
||||
self.pos_widget.screen_selector.show_popup('error-no-client');
|
||||
}else{
|
||||
self.pos_widget.screen_selector.show_popup('error-invoice-transfer');
|
||||
}
|
||||
self.pos_widget.action_bar.set_button_disabled('validation',false);
|
||||
self.pos_widget.action_bar.set_button_disabled('invoice',false);
|
||||
});
|
||||
|
||||
invoiced.done(function(){
|
||||
self.pos_widget.action_bar.set_button_disabled('validation',false);
|
||||
self.pos_widget.action_bar.set_button_disabled('invoice',false);
|
||||
self.pos.get('selectedOrder').destroy();
|
||||
});
|
||||
|
||||
}else{
|
||||
this.pos_widget.screen_selector.set_current_screen(this.next_screen);
|
||||
this.pos.push_order(currentOrder)
|
||||
if(this.pos.iface_print_via_proxy){
|
||||
this.pos.proxy.print_receipt(currentOrder.export_for_printing());
|
||||
this.pos.get('selectedOrder').destroy(); //finish order and go back to scan screen
|
||||
}else{
|
||||
this.pos_widget.screen_selector.set_current_screen(this.next_screen);
|
||||
}
|
||||
}
|
||||
},
|
||||
bindPaymentLineEvents: function() {
|
||||
|
@ -985,6 +1056,7 @@ function openerp_pos_screens(instance, module){ //module is instance.point_of_sa
|
|||
|
||||
if(this.pos_widget.action_bar){
|
||||
this.pos_widget.action_bar.set_button_disabled('validation', remaining > 0.000001);
|
||||
this.pos_widget.action_bar.set_button_disabled('invoice', remaining > 0.000001);
|
||||
}
|
||||
},
|
||||
set_numpad_state: function(numpadState) {
|
||||
|
|
|
@ -838,6 +838,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
instance.web.blockUI();
|
||||
|
||||
this.pos = new module.PosModel(this.session);
|
||||
this.pos.pos_widget = this;
|
||||
this.pos_widget = this; //So that pos_widget's childs have pos_widget set automatically
|
||||
|
||||
this.numpad_visible = true;
|
||||
|
@ -952,6 +953,12 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
this.error_negative_price_popup = new module.ErrorNegativePricePopupWidget(this, {});
|
||||
this.error_negative_price_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
this.error_no_client_popup = new module.ErrorNoClientPopupWidget(this, {});
|
||||
this.error_no_client_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
this.error_invoice_transfer_popup = new module.ErrorInvoiceTransferPopupWidget(this, {});
|
||||
this.error_invoice_transfer_popup.appendTo($('.point-of-sale'));
|
||||
|
||||
// -------- Misc ---------
|
||||
|
||||
this.notification = new module.SynchNotificationWidget(this,{});
|
||||
|
@ -1013,6 +1020,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
'error-session': this.error_session_popup,
|
||||
'error-negative-price': this.error_negative_price_popup,
|
||||
'choose-receipt': this.choose_receipt_popup,
|
||||
'error-no-client': this.error_no_client_popup,
|
||||
'error-invoice-transfer': this.error_invoice_transfer_popup,
|
||||
},
|
||||
default_client_screen: 'welcome',
|
||||
default_cashier_screen: 'products',
|
||||
|
|
|
@ -336,11 +336,11 @@
|
|||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">The scanned product was not recognized<br /> Please wait, a cashier is on the way</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="button">
|
||||
Ok
|
||||
<div class="footer">
|
||||
<div class="button">
|
||||
Ok
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
@ -361,6 +361,33 @@
|
|||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorNoClientPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">An anonymous order cannot be invoiced</p>
|
||||
<div class="footer">
|
||||
<div class="button">
|
||||
Ok
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorInvoiceTransferPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
<p class="message">The Order could not be sent to the server for invoicing. Invoices cannot be generated
|
||||
in offline mode. Please check your internet connection and try again.</p>
|
||||
<div class="footer">
|
||||
<div class="button">
|
||||
Ok
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ErrorPopupWidget">
|
||||
<div class="modal-dialog">
|
||||
<div class="popup popup-help">
|
||||
|
@ -538,7 +565,6 @@
|
|||
<button class="paypad-button" t-att-cash-register-id="widget.cashRegister.get('id')">
|
||||
<t t-esc="widget.cashRegister.get('journal').name"/>
|
||||
</button>
|
||||
<br />
|
||||
</t>
|
||||
|
||||
<t t-name="OrderButtonWidget">
|
||||
|
|
|
@ -19,35 +19,17 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.project.tests.test_project_base import TestProjectBase
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.tests import common
|
||||
from openerp.tools import mute_logger
|
||||
|
||||
|
||||
class TestPortalProject(common.TransactionCase):
|
||||
class TestPortalProjectBase(TestProjectBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortalProject, self).setUp()
|
||||
super(TestPortalProjectBase, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Useful models
|
||||
self.project_project = self.registry('project.project')
|
||||
self.project_task = self.registry('project.task')
|
||||
self.res_users = self.registry('res.users')
|
||||
self.res_partner = self.registry('res.partner')
|
||||
|
||||
# Find Employee group
|
||||
group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user')
|
||||
self.group_employee_id = group_employee_ref and group_employee_ref[1] or False
|
||||
|
||||
# Find Project User group
|
||||
group_project_user_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_user')
|
||||
self.group_project_user_id = group_project_user_ref and group_project_user_ref[1] or False
|
||||
|
||||
# Find Project Manager group
|
||||
group_project_manager_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_manager')
|
||||
self.group_project_manager_id = group_project_manager_ref and group_project_manager_ref[1] or False
|
||||
|
||||
# Find Portal group
|
||||
group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')
|
||||
self.group_portal_id = group_portal_ref and group_portal_ref[1] or False
|
||||
|
@ -56,62 +38,39 @@ class TestPortalProject(common.TransactionCase):
|
|||
group_anonymous_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_anonymous')
|
||||
self.group_anonymous_id = group_anonymous_ref and group_anonymous_ref[1] or False
|
||||
|
||||
# Test users to use through the various tests
|
||||
self.user_alfred_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Alfred EmployeeUser',
|
||||
'login': 'alfred',
|
||||
'alias_name': 'alfred',
|
||||
'groups_id': [(6, 0, [self.group_employee_id, self.group_project_user_id])]
|
||||
})
|
||||
self.user_bert_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Bert Nobody',
|
||||
'login': 'bert',
|
||||
'alias_name': 'bert',
|
||||
'groups_id': [(6, 0, [])]
|
||||
})
|
||||
self.user_chell_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Chell Portal',
|
||||
'login': 'chell',
|
||||
'alias_name': 'chell',
|
||||
'groups_id': [(6, 0, [self.group_portal_id])]
|
||||
})
|
||||
self.user_donovan_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Donovan Anonymous',
|
||||
'login': 'donovan',
|
||||
'alias_name': 'donovan',
|
||||
'groups_id': [(6, 0, [self.group_anonymous_id])]
|
||||
})
|
||||
self.user_ernest_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Ernest Manager',
|
||||
'login': 'ernest',
|
||||
'alias_name': 'ernest',
|
||||
'groups_id': [(6, 0, [self.group_project_manager_id])]
|
||||
})
|
||||
# # Test users to use through the various tests
|
||||
self.user_portal_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Chell Portal',
|
||||
'login': 'chell',
|
||||
'alias_name': 'chell',
|
||||
'groups_id': [(6, 0, [self.group_portal_id])]
|
||||
})
|
||||
self.user_anonymous_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Donovan Anonymous',
|
||||
'login': 'donovan',
|
||||
'alias_name': 'donovan',
|
||||
'groups_id': [(6, 0, [self.group_anonymous_id])]
|
||||
})
|
||||
|
||||
# Test 'Pigs' project
|
||||
self.project_pigs_id = self.project_project.create(cr, uid,
|
||||
{'name': 'Pigs', 'privacy_visibility': 'public'},
|
||||
{'mail_create_nolog': True})
|
||||
self.project_pigs_id = self.project_project.create(cr, uid, {
|
||||
'name': 'Pigs', 'privacy_visibility': 'public'}, {'mail_create_nolog': True})
|
||||
# Various test tasks
|
||||
self.task_1_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_2_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_3_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_4_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test4', 'user_id': self.user_alfred_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_5_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test5', 'user_id': self.user_chell_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_6_id = self.project_task.create(cr, uid,
|
||||
{'name': 'Test6', 'user_id': self.user_donovan_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.task_1_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.task_2_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.task_3_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.task_4_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test4', 'user_id': self.user_projectuser_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.task_5_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test5', 'user_id': self.user_portal_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.task_6_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Test6', 'user_id': self.user_anonymous_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
|
||||
|
||||
class TestPortalProject(TestPortalProjectBase):
|
||||
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
|
||||
def test_00_project_access_rights(self):
|
||||
""" Test basic project access rights, for project and portal_project """
|
||||
|
@ -122,53 +81,47 @@ class TestPortalProject(common.TransactionCase):
|
|||
# ----------------------------------------
|
||||
|
||||
# Do: Alfred reads project -> ok (employee ok public)
|
||||
self.project_project.read(cr, self.user_alfred_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||
# Test: all project tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_1_id, self.task_2_id, self.task_3_id, self.task_4_id, self.task_5_id, self.task_6_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: project user cannot see all tasks of a public project')
|
||||
'access rights: project user cannot see all tasks of a public project')
|
||||
# Test: all project tasks readable
|
||||
self.project_task.read(cr, self.user_alfred_id, task_ids, ['name'])
|
||||
self.project_task.read(cr, self.user_projectuser_id, task_ids, ['name'])
|
||||
# Test: all project tasks writable
|
||||
self.project_task.write(cr, self.user_alfred_id, task_ids, {'description': 'TestDescription'})
|
||||
self.project_task.write(cr, self.user_projectuser_id, task_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_bert_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_none_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
self.assertRaises(except_orm, self.project_task.search,
|
||||
cr, self.user_bert_id, [('project_id', '=', pigs_id)])
|
||||
self.assertRaises(except_orm, self.project_task.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
|
||||
# Test: no project task readable
|
||||
self.assertRaises(except_orm, self.project_task.read,
|
||||
cr, self.user_bert_id, task_ids, ['name'])
|
||||
self.assertRaises(except_orm, self.project_task.read, cr, self.user_none_id, task_ids, ['name'])
|
||||
# Test: no project task writable
|
||||
self.assertRaises(except_orm, self.project_task.write,
|
||||
cr, self.user_bert_id, task_ids, {'description': 'TestDescription'})
|
||||
self.assertRaises(except_orm, self.project_task.write, cr, self.user_none_id, task_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Chell reads project -> ok (portal ok public)
|
||||
self.project_project.read(cr, self.user_chell_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_portal_id, pigs_id, ['name'])
|
||||
# Test: all project tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: project user cannot see all tasks of a public project')
|
||||
'access rights: project user cannot see all tasks of a public project')
|
||||
# Test: all project tasks readable
|
||||
self.project_task.read(cr, self.user_chell_id, task_ids, ['name'])
|
||||
self.project_task.read(cr, self.user_portal_id, task_ids, ['name'])
|
||||
# Test: no project task writable
|
||||
self.assertRaises(except_orm, self.project_task.write,
|
||||
cr, self.user_chell_id, task_ids, {'description': 'TestDescription'})
|
||||
self.assertRaises(except_orm, self.project_task.write, cr, self.user_portal_id, task_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Donovan reads project -> ok (anonymous ok public)
|
||||
self.project_project.read(cr, self.user_donovan_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_anonymous_id, pigs_id, ['name'])
|
||||
# Test: all project tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_donovan_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_anonymous_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: anonymous user cannot see all tasks of a public project')
|
||||
'access rights: anonymous user cannot see all tasks of a public project')
|
||||
# Test: all project tasks readable
|
||||
self.project_task.read(cr, self.user_donovan_id, task_ids, ['name'])
|
||||
self.project_task.read(cr, self.user_anonymous_id, task_ids, ['name'])
|
||||
# Test: no project task writable
|
||||
self.assertRaises(except_orm, self.project_task.write,
|
||||
cr, self.user_donovan_id, task_ids, {'description': 'TestDescription'})
|
||||
self.assertRaises(except_orm, self.project_task.write, cr, self.user_anonymous_id, task_ids, {'description': 'TestDescription'})
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE2: portal project
|
||||
|
@ -176,39 +129,36 @@ class TestPortalProject(common.TransactionCase):
|
|||
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'portal'})
|
||||
|
||||
# Do: Alfred reads project -> ok (employee ok public)
|
||||
self.project_project.read(cr, self.user_alfred_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||
# Test: all project tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: project user cannot see all tasks of a portal project')
|
||||
'access rights: project user cannot see all tasks of a portal project')
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_bert_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_none_id, pigs_id, ['name'])
|
||||
# Test: no project task searchable
|
||||
self.assertRaises(except_orm, self.project_task.search,
|
||||
cr, self.user_bert_id, [('project_id', '=', pigs_id)])
|
||||
self.assertRaises(except_orm, self.project_task.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
|
||||
|
||||
# Data: task follower
|
||||
self.project_task.message_subscribe_users(cr, self.user_alfred_id, [self.task_1_id, self.task_3_id], [self.user_chell_id])
|
||||
self.project_task.message_subscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id])
|
||||
|
||||
# Do: Chell reads project -> ok (portal ok public)
|
||||
self.project_project.read(cr, self.user_chell_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_portal_id, pigs_id, ['name'])
|
||||
# Test: only followed project tasks visible + assigned
|
||||
task_ids = self.project_task.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_1_id, self.task_3_id, self.task_5_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: portal user should see the followed tasks of a portal project')
|
||||
'access rights: portal user should see the followed tasks of a portal project')
|
||||
|
||||
# Do: Donovan reads project -> ko (anonymous ko portal)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_donovan_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_anonymous_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
task_ids = self.project_task.search(cr, self.user_donovan_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_anonymous_id, [('project_id', '=', pigs_id)])
|
||||
self.assertFalse(task_ids, 'access rights: anonymous user should not see tasks of a portal project')
|
||||
|
||||
# Data: task follower cleaning
|
||||
self.project_task.message_unsubscribe_users(cr, self.user_alfred_id, [self.task_1_id, self.task_3_id], [self.user_chell_id])
|
||||
self.project_task.message_unsubscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id])
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE3: employee project
|
||||
|
@ -216,29 +166,26 @@ class TestPortalProject(common.TransactionCase):
|
|||
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'employees'})
|
||||
|
||||
# Do: Alfred reads project -> ok (employee ok employee)
|
||||
self.project_project.read(cr, self.user_alfred_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||
# Test: all project tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_1_id, self.task_2_id, self.task_3_id, self.task_4_id, self.task_5_id, self.task_6_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: project user cannot see all tasks of an employees project')
|
||||
'access rights: project user cannot see all tasks of an employees project')
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_bert_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_none_id, pigs_id, ['name'])
|
||||
|
||||
# Do: Chell reads project -> ko (portal ko employee)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_chell_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_portal_id, pigs_id, ['name'])
|
||||
# Test: no project task visible + assigned
|
||||
task_ids = self.project_task.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
self.assertFalse(task_ids, 'access rights: portal user should not see tasks of an employees project, even if assigned')
|
||||
|
||||
# Do: Donovan reads project -> ko (anonymous ko employee)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_donovan_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_anonymous_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
task_ids = self.project_task.search(cr, self.user_donovan_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_anonymous_id, [('project_id', '=', pigs_id)])
|
||||
self.assertFalse(task_ids, 'access rights: anonymous user should not see tasks of an employees project')
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -247,54 +194,49 @@ class TestPortalProject(common.TransactionCase):
|
|||
self.project_project.write(cr, uid, [pigs_id], {'privacy_visibility': 'followers'})
|
||||
|
||||
# Do: Alfred reads project -> ko (employee ko followers)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_alfred_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
task_ids = self.project_task.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_4_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: employee user should not see tasks of a not-followed followers project, only assigned')
|
||||
'access rights: employee user should not see tasks of a not-followed followers project, only assigned')
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_bert_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_none_id, pigs_id, ['name'])
|
||||
|
||||
# Do: Chell reads project -> ko (portal ko employee)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_chell_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_portal_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
task_ids = self.project_task.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_5_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: portal user should not see tasks of a not-followed followers project, only assigned')
|
||||
'access rights: portal user should not see tasks of a not-followed followers project, only assigned')
|
||||
|
||||
# Do: Donovan reads project -> ko (anonymous ko employee)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_donovan_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_anonymous_id, pigs_id, ['name'])
|
||||
# Test: no project task visible
|
||||
task_ids = self.project_task.search(cr, self.user_donovan_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_anonymous_id, [('project_id', '=', pigs_id)])
|
||||
self.assertFalse(task_ids, 'access rights: anonymous user should not see tasks of a followers project')
|
||||
|
||||
# Data: subscribe Alfred, Chell and Donovan as follower
|
||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_alfred_id, self.user_chell_id, self.user_donovan_id])
|
||||
self.project_task.message_subscribe_users(cr, self.user_alfred_id, [self.task_1_id, self.task_3_id], [self.user_chell_id, self.user_alfred_id])
|
||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
||||
self.project_task.message_subscribe_users(cr, self.user_projectuser_id, [self.task_1_id, self.task_3_id], [self.user_portal_id, self.user_projectuser_id])
|
||||
|
||||
# Do: Alfred reads project -> ok (follower ok followers)
|
||||
self.project_project.read(cr, self.user_alfred_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_projectuser_id, pigs_id, ['name'])
|
||||
# Test: followed + assigned tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_1_id, self.task_3_id, self.task_4_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: employee user should not see followed + assigned tasks of a follower project')
|
||||
'access rights: employee user should not see followed + assigned tasks of a follower project')
|
||||
|
||||
# Do: Chell reads project -> ok (follower ok follower)
|
||||
self.project_project.read(cr, self.user_chell_id, pigs_id, ['name'])
|
||||
self.project_project.read(cr, self.user_portal_id, pigs_id, ['name'])
|
||||
# Test: followed + assigned tasks visible
|
||||
task_ids = self.project_task.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
task_ids = self.project_task.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_task_ids = set([self.task_1_id, self.task_3_id, self.task_5_id])
|
||||
self.assertEqual(set(task_ids), test_task_ids,
|
||||
'access rights: employee user should not see followed + assigned tasks of a follower project')
|
||||
'access rights: employee user should not see followed + assigned tasks of a follower project')
|
||||
|
||||
# Do: Donovan reads project -> ko (anonymous ko follower even if follower)
|
||||
self.assertRaises(except_orm, self.project_project.read,
|
||||
cr, self.user_donovan_id, pigs_id, ['name'])
|
||||
self.assertRaises(except_orm, self.project_project.read, cr, self.user_anonymous_id, pigs_id, ['name'])
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</div>
|
||||
<div><field name="categ_ids" widget="many2many_tags" class="oe_left"/></div>
|
||||
<div class="oe_text_right">
|
||||
<h1><field name="state" readonly="1"/></h1>
|
||||
<h1><field name="stage_id" readonly="1"/></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -19,40 +19,36 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.portal_project.tests.test_access_rights import TestPortalProject
|
||||
from openerp.addons.portal_project.tests.test_access_rights import TestPortalProjectBase
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.tools import mute_logger
|
||||
|
||||
|
||||
class TestPortalIssueProject(TestPortalProject):
|
||||
class TestPortalProjectBase(TestPortalProjectBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPortalIssueProject, self).setUp()
|
||||
super(TestPortalProjectBase, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Useful models
|
||||
self.project_issue = self.registry('project.issue')
|
||||
|
||||
# Various test issues
|
||||
self.issue_1_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_2_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_3_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_4_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test4', 'user_id': self.user_alfred_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_5_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test5', 'user_id': self.user_chell_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_6_id = self.project_issue.create(cr, uid,
|
||||
{'name': 'Test6', 'user_id': self.user_donovan_id, 'project_id': self.project_pigs_id},
|
||||
{'mail_create_nolog': True})
|
||||
self.issue_1_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test1', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.issue_2_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test2', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.issue_3_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test3', 'user_id': False, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.issue_4_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test4', 'user_id': self.user_projectuser_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.issue_5_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test5', 'user_id': self.user_portal_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
self.issue_6_id = self.project_issue.create(cr, uid, {
|
||||
'name': 'Test6', 'user_id': self.user_anonymous_id, 'project_id': self.project_pigs_id}, {'mail_create_nolog': True})
|
||||
|
||||
|
||||
class TestPortalIssue(TestPortalProjectBase):
|
||||
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
|
||||
def test_00_project_access_rights(self):
|
||||
""" Test basic project access rights, for project and portal_project """
|
||||
|
@ -64,42 +60,38 @@ class TestPortalIssueProject(TestPortalProject):
|
|||
|
||||
# Do: Alfred reads project -> ok (employee ok public)
|
||||
# Test: all project issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_1_id, self.issue_2_id, self.issue_3_id, self.issue_4_id, self.issue_5_id, self.issue_6_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
# Test: all project issues readable
|
||||
self.project_issue.read(cr, self.user_alfred_id, issue_ids, ['name'])
|
||||
self.project_issue.read(cr, self.user_projectuser_id, issue_ids, ['name'])
|
||||
# Test: all project issues writable
|
||||
self.project_issue.write(cr, self.user_alfred_id, issue_ids, {'description': 'TestDescription'})
|
||||
self.project_issue.write(cr, self.user_projectuser_id, issue_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
# Test: no project issue visible
|
||||
self.assertRaises(except_orm, self.project_issue.search,
|
||||
cr, self.user_bert_id, [('project_id', '=', pigs_id)])
|
||||
self.assertRaises(except_orm, self.project_issue.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
|
||||
# Test: no project issue readable
|
||||
self.assertRaises(except_orm, self.project_issue.read,
|
||||
cr, self.user_bert_id, issue_ids, ['name'])
|
||||
self.assertRaises(except_orm, self.project_issue.read, cr, self.user_none_id, issue_ids, ['name'])
|
||||
# Test: no project issue writable
|
||||
self.assertRaises(except_orm, self.project_issue.write,
|
||||
cr, self.user_bert_id, issue_ids, {'description': 'TestDescription'})
|
||||
self.assertRaises(except_orm, self.project_issue.write, cr, self.user_none_id, issue_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Chell reads project -> ok (portal ok public)
|
||||
# Test: all project issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
# Test: all project issues readable
|
||||
self.project_issue.read(cr, self.user_chell_id, issue_ids, ['name'])
|
||||
self.project_issue.read(cr, self.user_portal_id, issue_ids, ['name'])
|
||||
# Test: no project issue writable
|
||||
self.assertRaises(except_orm, self.project_issue.write,
|
||||
cr, self.user_chell_id, issue_ids, {'description': 'TestDescription'})
|
||||
self.assertRaises(except_orm, self.project_issue.write, cr, self.user_portal_id, issue_ids, {'description': 'TestDescription'})
|
||||
|
||||
# Do: Donovan reads project -> ok (anonymous ok public)
|
||||
# Test: all project issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_donovan_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_anonymous_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
'access rights: project user cannot see all issues of a public project')
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE2: portal project
|
||||
|
@ -108,27 +100,26 @@ class TestPortalIssueProject(TestPortalProject):
|
|||
|
||||
# Do: Alfred reads project -> ok (employee ok public)
|
||||
# Test: all project issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: project user cannot see all issues of a portal project')
|
||||
'access rights: project user cannot see all issues of a portal project')
|
||||
|
||||
# Do: Bert reads project -> crash, no group
|
||||
# Test: no project issue searchable
|
||||
self.assertRaises(except_orm, self.project_issue.search,
|
||||
cr, self.user_bert_id, [('project_id', '=', pigs_id)])
|
||||
self.assertRaises(except_orm, self.project_issue.search, cr, self.user_none_id, [('project_id', '=', pigs_id)])
|
||||
|
||||
# Data: issue follower
|
||||
self.project_issue.message_subscribe_users(cr, self.user_alfred_id, [self.issue_1_id, self.issue_3_id], [self.user_chell_id])
|
||||
self.project_issue.message_subscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id])
|
||||
|
||||
# Do: Chell reads project -> ok (portal ok public)
|
||||
# Test: only followed project issues visible + assigned
|
||||
issue_ids = self.project_issue.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_5_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: portal user should see the followed issues of a portal project')
|
||||
'access rights: portal user should see the followed issues of a portal project')
|
||||
|
||||
# Data: issue follower cleaning
|
||||
self.project_issue.message_unsubscribe_users(cr, self.user_alfred_id, [self.issue_1_id, self.issue_3_id], [self.user_chell_id])
|
||||
self.project_issue.message_unsubscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id])
|
||||
|
||||
# ----------------------------------------
|
||||
# CASE3: employee project
|
||||
|
@ -137,14 +128,14 @@ class TestPortalIssueProject(TestPortalProject):
|
|||
|
||||
# Do: Alfred reads project -> ok (employee ok employee)
|
||||
# Test: all project issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_1_id, self.issue_2_id, self.issue_3_id, self.issue_4_id, self.issue_5_id, self.issue_6_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: project user cannot see all issues of an employees project')
|
||||
'access rights: project user cannot see all issues of an employees project')
|
||||
|
||||
# Do: Chell reads project -> ko (portal ko employee)
|
||||
# Test: no project issue visible + assigned
|
||||
issue_ids = self.project_issue.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
self.assertFalse(issue_ids, 'access rights: portal user should not see issues of an employees project, even if assigned')
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -154,32 +145,32 @@ class TestPortalIssueProject(TestPortalProject):
|
|||
|
||||
# Do: Alfred reads project -> ko (employee ko followers)
|
||||
# Test: no project issue visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_4_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: employee user should not see issues of a not-followed followers project, only assigned')
|
||||
'access rights: employee user should not see issues of a not-followed followers project, only assigned')
|
||||
|
||||
# Do: Chell reads project -> ko (portal ko employee)
|
||||
# Test: no project issue visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_5_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: portal user should not see issues of a not-followed followers project, only assigned')
|
||||
'access rights: portal user should not see issues of a not-followed followers project, only assigned')
|
||||
|
||||
# Data: subscribe Alfred, Chell and Donovan as follower
|
||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_alfred_id, self.user_chell_id, self.user_donovan_id])
|
||||
self.project_issue.message_subscribe_users(cr, self.user_alfred_id, [self.issue_1_id, self.issue_3_id], [self.user_chell_id, self.user_alfred_id])
|
||||
self.project_project.message_subscribe_users(cr, uid, [pigs_id], [self.user_projectuser_id, self.user_portal_id, self.user_anonymous_id])
|
||||
self.project_issue.message_subscribe_users(cr, self.user_projectuser_id, [self.issue_1_id, self.issue_3_id], [self.user_portal_id, self.user_projectuser_id])
|
||||
|
||||
# Do: Alfred reads project -> ok (follower ok followers)
|
||||
# Test: followed + assigned issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_alfred_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_projectuser_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_4_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: employee user should not see followed + assigned issues of a follower project')
|
||||
'access rights: employee user should not see followed + assigned issues of a follower project')
|
||||
|
||||
# Do: Chell reads project -> ok (follower ok follower)
|
||||
# Test: followed + assigned issues visible
|
||||
issue_ids = self.project_issue.search(cr, self.user_chell_id, [('project_id', '=', pigs_id)])
|
||||
issue_ids = self.project_issue.search(cr, self.user_portal_id, [('project_id', '=', pigs_id)])
|
||||
test_issue_ids = set([self.issue_1_id, self.issue_3_id, self.issue_5_id])
|
||||
self.assertEqual(set(issue_ids), test_issue_ids,
|
||||
'access rights: employee user should not see followed + assigned issues of a follower project')
|
||||
'access rights: employee user should not see followed + assigned issues of a follower project')
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
],
|
||||
'depends': [
|
||||
'base_setup',
|
||||
'base_status',
|
||||
'product',
|
||||
'analytic',
|
||||
'board',
|
||||
|
@ -66,7 +65,6 @@ Dashboard / Reports for Project Management will include:
|
|||
'data': [
|
||||
'security/project_security.xml',
|
||||
'wizard/project_task_delegate_view.xml',
|
||||
'wizard/project_task_reevaluate_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'project_data.xml',
|
||||
'project_view.xml',
|
||||
|
@ -79,9 +77,6 @@ Dashboard / Reports for Project Management will include:
|
|||
],
|
||||
'demo': ['project_demo.xml'],
|
||||
'test': [
|
||||
'test/project_demo.yml',
|
||||
'test/project_process.yml',
|
||||
'test/task_process.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="stage_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -26,7 +25,7 @@
|
|||
<field name="res_model">project.task</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('user_id','=',uid),('state','not in',('cancel','done'))]</field>
|
||||
<field name="domain">[('user_id', '=', uid), ('stage_id.fold', '!=', True)]</field>
|
||||
<field name="view_id" ref="view_task_tree"/>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
.. _changelog:
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
`trunk (saas-2)`
|
||||
----------------
|
||||
|
||||
- Stage/state update
|
||||
|
||||
- ``project.task``: removed inheritance from ``base_stage`` class and removed
|
||||
``state`` field. Added ``date_last_stage_update`` field holding last stage_id
|
||||
modification. Updated reports.
|
||||
- ``project.task.type``: removed ``state`` field.
|
||||
|
||||
- Removed ``project.task.reevaluate`` wizard.
|
|
@ -0,0 +1,22 @@
|
|||
=====================
|
||||
Project DevDoc
|
||||
=====================
|
||||
|
||||
Project module documentation
|
||||
===================================
|
||||
|
||||
Documentation topics
|
||||
''''''''''''''''''''
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
stage_status.rst
|
||||
|
||||
Changelog
|
||||
'''''''''
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
changelog.rst
|
|
@ -0,0 +1,55 @@
|
|||
.. _stage_status:
|
||||
|
||||
Stage and Status
|
||||
================
|
||||
|
||||
.. versionchanged:: 8.0 saas-2 state/stage cleaning
|
||||
|
||||
Stage
|
||||
+++++
|
||||
|
||||
This revision removed the concept of state on project.task objects. The ``state``
|
||||
field has been totally removed and replaced by stages, using ``stage_id``. The
|
||||
following models are impacted:
|
||||
|
||||
- ``project.task`` now use only stages. However a convention still exists about
|
||||
'New' stage. A task is consdered as ``new`` when it has the following
|
||||
properties:
|
||||
|
||||
- ``stage_id and stage_id.sequence = 1``
|
||||
|
||||
- ``project.task.type`` do not have any ``state`` field anymore.
|
||||
- ``project.task.report`` do not have any ``state`` field anymore.
|
||||
|
||||
By default a newly created task is in a new stage. It means that it will
|
||||
fetch the stage having ``sequence = 1``. Stage mangement is done using the
|
||||
kanban view or the clikable statusbar. It is not done using buttons anymore.
|
||||
|
||||
Stage analysis
|
||||
++++++++++++++
|
||||
|
||||
Stage analysis can be performed using the newly introduced ``date_last_stage_update``
|
||||
datetime field. This field is updated everytime ``stage_id`` is updated.
|
||||
|
||||
``project.task.report`` model also uses the ``date_last_stage_update`` field.
|
||||
This allows to group and analyse the time spend in the various stages.
|
||||
|
||||
Open / Assignation date
|
||||
+++++++++++++++++++++++
|
||||
|
||||
The ``date_open`` field meaning has been updated. It is now set when the ``user_id``
|
||||
(responsible) is set. It is therefore the assignation date.
|
||||
|
||||
Subtypes
|
||||
++++++++
|
||||
|
||||
The following subtypes are triggered on ``project.task``:
|
||||
|
||||
- ``mt_task_new``: new tasks. Condition: ``obj.stage_id and obj.stage_id.sequence == 1``
|
||||
- ``mt_task_stage``: stage changed. Condition: ``obj.stage_id and obj.stage_id.sequence != 1``
|
||||
- ``mt_task_assigned``: user assigned. condition: ``obj.user_id and obj.user_id.id``
|
||||
- ``mt_task_blocked``: kanban state blocked. Condition: ``obj.kanban_state == 'blocked'``
|
||||
|
||||
|
||||
Those subtypes are also available on the ``project.project`` model and are used
|
||||
for the auto subscription.
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 6.0dev\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2013-07-08 14:09+0000\n"
|
||||
"PO-Revision-Date: 2013-07-14 04:15+0000\n"
|
||||
"Last-Translator: Alan <shuchuan.wu@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-09 05:16+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-15 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build 16696)\n"
|
||||
|
||||
#. module: project
|
||||
|
@ -458,7 +458,7 @@ msgstr "延期的任务"
|
|||
#. module: project
|
||||
#: view:project.task:0
|
||||
msgid "Delegation"
|
||||
msgstr "代表"
|
||||
msgstr "任务委派"
|
||||
|
||||
#. module: project
|
||||
#: field:project.task,create_date:0
|
||||
|
@ -636,6 +636,15 @@ msgid ""
|
|||
" </p>\n"
|
||||
" "
|
||||
msgstr ""
|
||||
"<p class=\"oe_view_nocontent_create\">\n"
|
||||
" 创建一个新项目\n"
|
||||
" </p><p>\n"
|
||||
" "
|
||||
"项目是组织活动,计划任务,跟踪问题,记录人力资源成本的组织形式。项目可以分为内部项目(研发活动,加快销售进度),私有项目或者客户参与的项目。\n"
|
||||
" </p><p>\n"
|
||||
" 内部用户以项目成员的方式参与到项目中,也可以邀请客户加入到项目中分享项目活动。\n"
|
||||
" </p>\n"
|
||||
" "
|
||||
|
||||
#. module: project
|
||||
#: view:project.config.settings:0
|
||||
|
@ -647,7 +656,7 @@ msgstr "计划"
|
|||
#: field:project.task,date_deadline:0
|
||||
#: field:report.project.task.user,date_deadline:0
|
||||
msgid "Deadline"
|
||||
msgstr "最后期限"
|
||||
msgstr "计划完成日期"
|
||||
|
||||
#. module: project
|
||||
#: view:project.task.history.cumulative:0
|
||||
|
@ -1137,7 +1146,7 @@ msgstr "您的文档的状态将自动更改选定的阶段。例如,如果某
|
|||
#. module: project
|
||||
#: view:project.task:0
|
||||
msgid "Extra Info"
|
||||
msgstr "额外信息"
|
||||
msgstr "其它信息"
|
||||
|
||||
#. module: project
|
||||
#: view:project.task:0
|
||||
|
@ -1479,7 +1488,7 @@ msgstr "总小时数"
|
|||
#. module: project
|
||||
#: model:ir.model,name:project.model_project_config_settings
|
||||
msgid "project.config.settings"
|
||||
msgstr ""
|
||||
msgstr "项目配置"
|
||||
|
||||
#. module: project
|
||||
#: model:project.task.type,name:project.project_tt_development
|
||||
|
@ -1717,7 +1726,7 @@ msgstr "文档"
|
|||
#. module: project
|
||||
#: model:mail.message.subtype,description:project.mt_task_new
|
||||
msgid "Task created"
|
||||
msgstr ""
|
||||
msgstr "任务已创建"
|
||||
|
||||
#. module: project
|
||||
#: view:report.project.task.user:0
|
||||
|
@ -1981,7 +1990,7 @@ msgstr "请删除与此科目关联的项目"
|
|||
#: model:mail.message.subtype,name:project.mt_project_task_new
|
||||
#: model:mail.message.subtype,name:project.mt_task_new
|
||||
msgid "Task Created"
|
||||
msgstr ""
|
||||
msgstr "任务已创建"
|
||||
|
||||
#. module: project
|
||||
#: view:report.project.task.user:0
|
||||
|
@ -2046,7 +2055,7 @@ msgstr ""
|
|||
#. module: project
|
||||
#: model:mail.message.subtype,description:project.mt_task_closed
|
||||
msgid "Task closed"
|
||||
msgstr ""
|
||||
msgstr "已关闭的任务"
|
||||
|
||||
#. module: project
|
||||
#: selection:report.project.task.user,month:0
|
||||
|
|
|
@ -25,13 +25,10 @@ import time
|
|||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.addons.resource.faces import task as Task
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
from openerp.addons.base_status.base_stage import base_stage
|
||||
from openerp.addons.resource.faces import task as Task
|
||||
|
||||
_TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')]
|
||||
|
||||
class project_task_type(osv.osv):
|
||||
_name = 'project.task.type'
|
||||
|
@ -44,33 +41,18 @@ class project_task_type(osv.osv):
|
|||
'case_default': fields.boolean('Default for New Projects',
|
||||
help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."),
|
||||
'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
|
||||
'state': fields.selection(_TASK_STATE, 'Related Status', required=True,
|
||||
help="The status of your document is automatically changed regarding the selected stage. " \
|
||||
"For example, if a stage is related to the status 'Close', when your document reaches this stage, it is automatically closed."),
|
||||
'fold': fields.boolean('Folded by Default',
|
||||
help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
|
||||
}
|
||||
def _get_default_project_id(self, cr, uid, ctx={}):
|
||||
proj = ctx.get('default_project_id', False)
|
||||
if type(proj) is int:
|
||||
return [proj]
|
||||
return proj
|
||||
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
'state': 'open',
|
||||
'fold': False,
|
||||
'case_default': False,
|
||||
'project_ids': _get_default_project_id
|
||||
'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.task']._get_default_project_id(cr, uid, context=ctx),
|
||||
}
|
||||
_order = 'sequence'
|
||||
|
||||
def short_name(name):
|
||||
"""Keep first word(s) of name to make it small enough
|
||||
but distinctive"""
|
||||
if not name: return name
|
||||
# keep 7 chars + end of the last word
|
||||
keep_words = name[:7].strip().split()
|
||||
return ' '.join(name.split()[:len(keep_words)])
|
||||
|
||||
class project(osv.osv):
|
||||
_name = "project.project"
|
||||
|
@ -99,9 +81,9 @@ class project(osv.osv):
|
|||
|
||||
def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
if not part:
|
||||
return {'value':{}}
|
||||
val = {}
|
||||
if not part:
|
||||
return {'value': val}
|
||||
if 'pricelist_id' in self.fields_get(cr, uid, context=context):
|
||||
pricelist = partner_obj.read(cr, uid, part, ['property_product_pricelist'], context=context)
|
||||
pricelist_id = pricelist.get('property_product_pricelist', False) and pricelist.get('property_product_pricelist')[0] or False
|
||||
|
@ -152,11 +134,13 @@ class project(osv.osv):
|
|||
cr.execute("""
|
||||
SELECT project_id, COALESCE(SUM(planned_hours), 0.0),
|
||||
COALESCE(SUM(total_hours), 0.0), COALESCE(SUM(effective_hours), 0.0)
|
||||
FROM project_task WHERE project_id IN %s AND state <> 'cancelled'
|
||||
FROM project_task
|
||||
LEFT JOIN project_task_type ON project_task.stage_id = project_task_type.id
|
||||
WHERE project_task.project_id IN %s AND project_task_type.fold = False
|
||||
GROUP BY project_id
|
||||
""", (tuple(child_parent.keys()),))
|
||||
# aggregate results into res
|
||||
res = dict([(id, {'planned_hours':0.0,'total_hours':0.0,'effective_hours':0.0}) for id in ids])
|
||||
res = dict([(id, {'planned_hours':0.0, 'total_hours':0.0, 'effective_hours':0.0}) for id in ids])
|
||||
for id, planned, total, effective in cr.fetchall():
|
||||
# add the values specific to id to all parent projects of id in the result
|
||||
while id:
|
||||
|
@ -253,22 +237,22 @@ class project(osv.osv):
|
|||
'planned_hours': fields.function(_progress_rate, multi="progress", string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.",
|
||||
store = {
|
||||
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20),
|
||||
}),
|
||||
'effective_hours': fields.function(_progress_rate, multi="progress", string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects.",
|
||||
store = {
|
||||
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20),
|
||||
}),
|
||||
'total_hours': fields.function(_progress_rate, multi="progress", string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects.",
|
||||
store = {
|
||||
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20),
|
||||
}),
|
||||
'progress_rate': fields.function(_progress_rate, multi="progress", string='Progress', type='float', group_operator="avg", help="Percent of tasks closed according to the total of tasks todo.",
|
||||
store = {
|
||||
'project.project': (_get_project_and_parents, ['tasks', 'parent_id', 'child_ids'], 10),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'state'], 20),
|
||||
'project.task': (_get_projects_from_tasks, ['planned_hours', 'remaining_hours', 'work_ids', 'stage_id'], 20),
|
||||
}),
|
||||
'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
|
||||
'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
|
@ -323,26 +307,19 @@ class project(osv.osv):
|
|||
]
|
||||
|
||||
def set_template(self, cr, uid, ids, context=None):
|
||||
res = self.setActive(cr, uid, ids, value=False, context=context)
|
||||
return res
|
||||
return self.setActive(cr, uid, ids, value=False, context=context)
|
||||
|
||||
def set_done(self, cr, uid, ids, context=None):
|
||||
task_obj = self.pool.get('project.task')
|
||||
task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', 'not in', ('cancelled', 'done'))])
|
||||
task_obj.case_close(cr, uid, task_ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state':'close'}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||
|
||||
def set_cancel(self, cr, uid, ids, context=None):
|
||||
task_obj = self.pool.get('project.task')
|
||||
task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', '!=', 'done')])
|
||||
task_obj.case_cancel(cr, uid, task_ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context)
|
||||
|
||||
def set_pending(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state':'pending'}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'pending'}, context=context)
|
||||
|
||||
def set_open(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state':'open'}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||
|
||||
def reset_project(self, cr, uid, ids, context=None):
|
||||
return self.setActive(cr, uid, ids, value=True, context=context)
|
||||
|
@ -459,8 +436,6 @@ class project(osv.osv):
|
|||
if project.user_id and (project.user_id.id not in u_ids):
|
||||
u_ids.append(project.user_id.id)
|
||||
for task in project.tasks:
|
||||
if task.state in ('done','cancelled'):
|
||||
continue
|
||||
if task.user_id and (task.user_id.id not in u_ids):
|
||||
u_ids.append(task.user_id.id)
|
||||
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
|
||||
|
@ -525,7 +500,7 @@ def Project():
|
|||
for project in projects:
|
||||
project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
|
||||
for task in project.tasks:
|
||||
if task.state in ('done', 'cancelled'):
|
||||
if task.stage_id and task.stage_id.fold:
|
||||
continue
|
||||
|
||||
p = getattr(project_gantt, 'Task_%d' % (task.id,))
|
||||
|
@ -540,16 +515,13 @@ def Project():
|
|||
}, context=context)
|
||||
return True
|
||||
|
||||
# ------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# ------------------------------------------------
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
# Prevent double project creation when 'use_tasks' is checked + alias management
|
||||
create_context = dict(context, project_creation_in_progress=True,
|
||||
alias_model_name=vals.get('alias_model', 'project.task'), alias_parent_model_name=self._name)
|
||||
alias_model_name=vals.get('alias_model', 'project.task'),
|
||||
alias_parent_model_name=self._name)
|
||||
|
||||
if vals.get('type', False) not in ('template', 'contract'):
|
||||
vals['type'] = 'contract'
|
||||
|
@ -566,22 +538,22 @@ def Project():
|
|||
vals.update(alias_model_id=model_ids[0])
|
||||
return super(project, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
class task(base_stage, osv.osv):
|
||||
|
||||
class task(osv.osv):
|
||||
_name = "project.task"
|
||||
_description = "Task"
|
||||
_date_name = "date_start"
|
||||
_inherit = ['mail.thread', 'ir.needaction_mixin']
|
||||
|
||||
_track = {
|
||||
'state': {
|
||||
'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.state in ['new', 'draft'],
|
||||
'project.mt_task_started': lambda self, cr, uid, obj, ctx=None: obj.state == 'open',
|
||||
'project.mt_task_closed': lambda self, cr, uid, obj, ctx=None: obj.state == 'done',
|
||||
},
|
||||
'stage_id': {
|
||||
'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.state not in ['new', 'draft', 'done', 'open'],
|
||||
'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1,
|
||||
'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id.sequence != 1,
|
||||
},
|
||||
'kanban_state': { # kanban state: tracked, but only block subtype
|
||||
'user_id': {
|
||||
'project.mt_task_assigned': lambda self, cr, uid, obj, ctx=None: obj.user_id and obj.user_id.id,
|
||||
},
|
||||
'kanban_state': {
|
||||
'project.mt_task_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked',
|
||||
},
|
||||
}
|
||||
|
@ -593,7 +565,7 @@ class task(base_stage, osv.osv):
|
|||
project = self.pool.get('project.project').browse(cr, uid, project_id, context=context)
|
||||
if project and project.partner_id:
|
||||
return project.partner_id.id
|
||||
return super(task, self)._get_default_partner(cr, uid, context=context)
|
||||
return False
|
||||
|
||||
def _get_default_project_id(self, cr, uid, context=None):
|
||||
""" Gives default section by checking if present in the context """
|
||||
|
@ -602,7 +574,7 @@ class task(base_stage, osv.osv):
|
|||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
""" Gives default stage_id """
|
||||
project_id = self._get_default_project_id(cr, uid, context=context)
|
||||
return self.stage_find(cr, uid, [], project_id, [('state', '=', 'draft')], context=context)
|
||||
return self.stage_find(cr, uid, [], project_id, [('sequence', '=', '1')], context=context)
|
||||
|
||||
def _resolve_project_id_from_context(self, cr, uid, context=None):
|
||||
""" Returns ID of project based on the value of 'default_project_id'
|
||||
|
@ -679,17 +651,18 @@ class task(base_stage, osv.osv):
|
|||
res[task.id]['progress'] = 0.0
|
||||
if (task.remaining_hours + hours.get(task.id, 0.0)):
|
||||
res[task.id]['progress'] = round(min(100.0 * hours.get(task.id, 0.0) / res[task.id]['total_hours'], 99.99),2)
|
||||
if task.state in ('done','cancelled'):
|
||||
# TDE CHECK: if task.state in ('done','cancelled'):
|
||||
if task.stage_id and task.stage_id.fold:
|
||||
res[task.id]['progress'] = 100.0
|
||||
return res
|
||||
|
||||
def onchange_remaining(self, cr, uid, ids, remaining=0.0, planned=0.0):
|
||||
if remaining and not planned:
|
||||
return {'value':{'planned_hours': remaining}}
|
||||
return {'value': {'planned_hours': remaining}}
|
||||
return {}
|
||||
|
||||
def onchange_planned(self, cr, uid, ids, planned=0.0, effective=0.0):
|
||||
return {'value':{'remaining_hours': planned - effective}}
|
||||
return {'value': {'remaining_hours': planned - effective}}
|
||||
|
||||
def onchange_project(self, cr, uid, id, project_id, context=None):
|
||||
if project_id:
|
||||
|
@ -698,6 +671,12 @@ class task(base_stage, osv.osv):
|
|||
return {'value': {'partner_id': project.partner_id.id}}
|
||||
return {}
|
||||
|
||||
def onchange_user_id(self, cr, uid, ids, user_id, context=None):
|
||||
vals = {}
|
||||
if user_id:
|
||||
vals['date_start'] = fields.datetime.now()
|
||||
return {'value': vals}
|
||||
|
||||
def duplicate_task(self, cr, uid, map_ids, context=None):
|
||||
for new in map_ids.values():
|
||||
task = self.browse(cr, uid, new, context)
|
||||
|
@ -755,13 +734,6 @@ class task(base_stage, osv.osv):
|
|||
'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage', track_visibility='onchange',
|
||||
domain="[('project_ids', '=', project_id)]"),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=_TASK_STATE, string="Status", readonly=True,
|
||||
help='The status is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the status is set to \'Open\'.\
|
||||
When the case is over, the status is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the status is \
|
||||
set to \'Pending\'.'),
|
||||
'categ_ids': fields.many2many('project.category', string='Tags'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
|
||||
track_visibility='onchange',
|
||||
|
@ -774,6 +746,7 @@ class task(base_stage, osv.osv):
|
|||
'date_start': fields.datetime('Starting Date',select=True),
|
||||
'date_end': fields.datetime('Ending Date',select=True),
|
||||
'date_deadline': fields.date('Deadline',select=True),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
|
||||
'project_id': fields.many2one('project.project', 'Project', ondelete='set null', select="1", track_visibility='onchange'),
|
||||
'parent_ids': fields.many2many('project.task', 'project_task_parent_rel', 'task_id', 'parent_id', 'Parent Tasks'),
|
||||
'child_ids': fields.many2many('project.task', 'project_task_parent_rel', 'parent_id', 'task_id', 'Delegated Tasks'),
|
||||
|
@ -790,7 +763,7 @@ class task(base_stage, osv.osv):
|
|||
'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10),
|
||||
'project.task.work': (_get_task, ['hours'], 10),
|
||||
}),
|
||||
'progress': fields.function(_hours_get, string='Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time",
|
||||
'progress': fields.function(_hours_get, string='Working Time Progress (%)', multi='hours', group_operator="avg", help="If the task has a progress of 99.99% you should close the task if it's finished or reevaluate the time",
|
||||
store = {
|
||||
'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours','state'], 10),
|
||||
'project.task.work': (_get_task, ['hours'], 10),
|
||||
|
@ -813,6 +786,7 @@ class task(base_stage, osv.osv):
|
|||
_defaults = {
|
||||
'stage_id': _get_default_stage_id,
|
||||
'project_id': _get_default_project_id,
|
||||
'date_last_stage_update': lambda *a: fields.datetime.now(),
|
||||
'kanban_state': 'normal',
|
||||
'priority': '2',
|
||||
'progress': 0,
|
||||
|
@ -940,7 +914,7 @@ class task(base_stage, osv.osv):
|
|||
section_ids.append(task.project_id.id)
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain = [('|')] * (len(section_ids)-1)
|
||||
search_domain = [('|')] * (len(section_ids) - 1)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('project_ids', '=', section_id))
|
||||
search_domain += list(domain)
|
||||
|
@ -957,82 +931,10 @@ class task(base_stage, osv.osv):
|
|||
for task in tasks:
|
||||
if task.child_ids:
|
||||
for child in task.child_ids:
|
||||
if child.state in ['draft', 'open', 'pending']:
|
||||
if child.stage_id and not child.stage_id.fold:
|
||||
raise osv.except_osv(_("Warning!"), _("Child task still open.\nPlease cancel or complete child task first."))
|
||||
return True
|
||||
|
||||
def action_close(self, cr, uid, ids, context=None):
|
||||
""" This action closes the task
|
||||
"""
|
||||
task_id = len(ids) and ids[0] or False
|
||||
self._check_child_task(cr, uid, ids, context=context)
|
||||
if not task_id: return False
|
||||
return self.do_close(cr, uid, [task_id], context=context)
|
||||
|
||||
def do_close(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_close. """
|
||||
return self.case_close(cr, uid, ids, context=context)
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
""" Closes Task """
|
||||
if not isinstance(ids, list): ids = [ids]
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
vals = {}
|
||||
project = task.project_id
|
||||
for parent_id in task.parent_ids:
|
||||
if parent_id.state in ('pending','draft'):
|
||||
reopen = True
|
||||
for child in parent_id.child_ids:
|
||||
if child.id != task.id and child.state not in ('done','cancelled'):
|
||||
reopen = False
|
||||
if reopen:
|
||||
self.do_reopen(cr, uid, [parent_id.id], context=context)
|
||||
# close task
|
||||
vals['remaining_hours'] = 0.0
|
||||
if not task.date_end:
|
||||
vals['date_end'] = fields.datetime.now()
|
||||
self.case_set(cr, uid, [task.id], 'done', vals, context=context)
|
||||
return True
|
||||
|
||||
def do_reopen(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
project = task.project_id
|
||||
self.case_set(cr, uid, [task.id], 'open', {}, context=context)
|
||||
return True
|
||||
|
||||
def do_cancel(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_cancel. """
|
||||
return self.case_cancel(cr, uid, ids, context=context)
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
tasks = self.browse(cr, uid, ids, context=context)
|
||||
self._check_child_task(cr, uid, ids, context=context)
|
||||
for task in tasks:
|
||||
self.case_set(cr, uid, [task.id], 'cancelled', {'remaining_hours': 0.0}, context=context)
|
||||
return True
|
||||
|
||||
def do_open(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_open. """
|
||||
return self.case_open(cr, uid, ids, context=context)
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
if not isinstance(ids,list): ids = [ids]
|
||||
return self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context)
|
||||
|
||||
def do_draft(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_draft. """
|
||||
return self.case_draft(cr, uid, ids, context=context)
|
||||
|
||||
def case_draft(self, cr, uid, ids, context=None):
|
||||
return self.case_set(cr, uid, ids, 'draft', {}, context=context)
|
||||
|
||||
def do_pending(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_pending. """
|
||||
return self.case_pending(cr, uid, ids, context=context)
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
return self.case_set(cr, uid, ids, 'pending', {}, context=context)
|
||||
|
||||
def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
|
||||
attachment = self.pool.get('ir.attachment')
|
||||
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context)
|
||||
|
@ -1053,6 +955,7 @@ class task(base_stage, osv.osv):
|
|||
delegated_task_id = self.copy(cr, uid, task.id, {
|
||||
'name': delegate_data['name'],
|
||||
'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False,
|
||||
'stage_id': delegate_data.get('stage_id') and delegate_data.get('stage_id')[0] or False,
|
||||
'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False,
|
||||
'planned_hours': delegate_data['planned_hours'] or 0.0,
|
||||
'parent_ids': [(6, 0, [task.id])],
|
||||
|
@ -1067,16 +970,12 @@ class task(base_stage, osv.osv):
|
|||
'planned_hours': delegate_data['planned_hours_me'] + (task.effective_hours or 0.0),
|
||||
'name': newname,
|
||||
}, context=context)
|
||||
if delegate_data['state'] == 'pending':
|
||||
self.do_pending(cr, uid, [task.id], context=context)
|
||||
elif delegate_data['state'] == 'done':
|
||||
self.do_close(cr, uid, [task.id], context=context)
|
||||
delegated_tasks[task.id] = delegated_task_id
|
||||
return delegated_tasks
|
||||
|
||||
def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
if (task.state=='draft') or (task.planned_hours==0.0):
|
||||
if (task.stage_id and task.stage_id.sequence == 1) or (task.planned_hours == 0.0):
|
||||
self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context)
|
||||
self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context)
|
||||
return True
|
||||
|
@ -1111,17 +1010,25 @@ class task(base_stage, osv.osv):
|
|||
'planned_hours': task.planned_hours,
|
||||
'kanban_state': task.kanban_state,
|
||||
'type_id': task.stage_id.id,
|
||||
'state': task.state,
|
||||
'user_id': task.user_id.id
|
||||
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
# ------------------------------------------------
|
||||
# CRUD overrides
|
||||
# ------------------------------------------------
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
# for default stage
|
||||
if vals.get('project_id') and not context.get('default_project_id'):
|
||||
context['default_project_id'] = vals.get('project_id')
|
||||
# user_id change: update date_start
|
||||
if vals.get('user_id'):
|
||||
vals['date_start'] = fields.datetime.now()
|
||||
|
||||
# context: no_log, because subtype already handle this
|
||||
create_context = dict(context, mail_create_nolog=True)
|
||||
|
@ -1129,25 +1036,30 @@ class task(base_stage, osv.osv):
|
|||
self._store_history(cr, uid, [task_id], context=context)
|
||||
return task_id
|
||||
|
||||
# Overridden to reset the kanban_state to normal whenever
|
||||
# the stage (stage_id) of the task changes.
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
|
||||
# stage change: update date_last_stage_update
|
||||
if 'stage_id' in vals:
|
||||
vals['date_last_stage_update'] = fields.datetime.now()
|
||||
# user_id change: update date_start
|
||||
if vals.get('user_id'):
|
||||
vals['date_start'] = fields.datetime.now()
|
||||
|
||||
# Overridden to reset the kanban_state to normal whenever
|
||||
# the stage (stage_id) of the task changes.
|
||||
if vals and not 'kanban_state' in vals and 'stage_id' in vals:
|
||||
new_stage = vals.get('stage_id')
|
||||
vals_reset_kstate = dict(vals, kanban_state='normal')
|
||||
for t in self.browse(cr, uid, ids, context=context):
|
||||
#TO FIX:Kanban view doesn't raise warning
|
||||
#stages = [stage.id for stage in t.project_id.type_ids]
|
||||
#if new_stage not in stages:
|
||||
#raise osv.except_osv(_('Warning!'), _('Stage is not defined in the project.'))
|
||||
write_vals = vals_reset_kstate if t.stage_id != new_stage else vals
|
||||
super(task, self).write(cr, uid, [t.id], write_vals, context=context)
|
||||
result = True
|
||||
else:
|
||||
result = super(task, self).write(cr, uid, ids, vals, context=context)
|
||||
if ('stage_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
|
||||
|
||||
if any(item in vals for item in ['stage_id', 'remaining_hours', 'user_id', 'kanban_state']):
|
||||
self._store_history(cr, uid, ids, context=context)
|
||||
return result
|
||||
|
||||
|
@ -1163,7 +1075,7 @@ class task(base_stage, osv.osv):
|
|||
result = ""
|
||||
ident = ' '*ident
|
||||
for task in tasks:
|
||||
if task.state in ('done','cancelled'):
|
||||
if task.stage_id and task.stage_id.fold:
|
||||
continue
|
||||
result += '''
|
||||
%sdef Task_%s():
|
||||
|
@ -1233,24 +1145,10 @@ class task(base_stage, osv.osv):
|
|||
update_vals[field] = float(res.group(2).lower())
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
elif match.lower() == 'state' \
|
||||
and res.group(2).lower() in ['cancel','close','draft','open','pending']:
|
||||
act = 'do_%s' % res.group(2).lower()
|
||||
if act:
|
||||
getattr(self,act)(cr, uid, ids, context=context)
|
||||
return super(task,self).message_update(cr, uid, ids, msg, update_vals=update_vals, context=context)
|
||||
|
||||
def project_task_reevaluate(self, cr, uid, ids, context=None):
|
||||
if self.pool.get('res.users').has_group(cr, uid, 'project.group_time_work_estimation_tasks'):
|
||||
return {
|
||||
'view_type': 'form',
|
||||
"view_mode": 'form',
|
||||
'res_model': 'project.task.reevaluate',
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
return self.do_reopen(cr, uid, ids, context=context)
|
||||
|
||||
class project_work(osv.osv):
|
||||
_name = "project.task.work"
|
||||
_description = "Project Task Work"
|
||||
|
@ -1371,7 +1269,7 @@ class project_task_history(osv.osv):
|
|||
def _get_date(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
for history in self.browse(cr, uid, ids, context=context):
|
||||
if history.state in ('done','cancelled'):
|
||||
if history.type_id and history.type_id.fold:
|
||||
result[history.id] = history.date
|
||||
continue
|
||||
cr.execute('''select
|
||||
|
@ -1405,14 +1303,13 @@ class project_task_history(osv.osv):
|
|||
_columns = {
|
||||
'task_id': fields.many2one('project.task', 'Task', ondelete='cascade', required=True, select=True),
|
||||
'type_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'state': fields.selection([('draft', 'New'), ('cancelled', 'Cancelled'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done')], 'Status'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State', required=False),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'), ('blocked', 'Blocked'), ('done', 'Ready for next stage')], 'Kanban State', required=False),
|
||||
'date': fields.date('Date', select=True),
|
||||
'end_date': fields.function(_get_date, string='End Date', type="date", store={
|
||||
'project.task.history': (_get_related_date, None, 20)
|
||||
}),
|
||||
'remaining_hours': fields.float('Remaining Time', digits=(16,2)),
|
||||
'planned_hours': fields.float('Planned Time', digits=(16,2)),
|
||||
'remaining_hours': fields.float('Remaining Time', digits=(16, 2)),
|
||||
'planned_hours': fields.float('Planned Time', digits=(16, 2)),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
}
|
||||
_defaults = {
|
||||
|
@ -1442,7 +1339,7 @@ class project_task_history_cumulative(osv.osv):
|
|||
SELECT
|
||||
h.id AS history_id,
|
||||
h.date+generate_series(0, CAST((coalesce(h.end_date, DATE 'tomorrow')::date - h.date) AS integer)-1) AS date,
|
||||
h.task_id, h.type_id, h.user_id, h.kanban_state, h.state,
|
||||
h.task_id, h.type_id, h.user_id, h.kanban_state,
|
||||
greatest(h.remaining_hours, 1) AS remaining_hours, greatest(h.planned_hours, 1) AS planned_hours,
|
||||
t.project_id
|
||||
FROM
|
||||
|
|
|
@ -30,51 +30,43 @@
|
|||
<record id="project_tt_analysis" model="project.task.type">
|
||||
<field name="sequence">1</field>
|
||||
<field name="name">Analysis</field>
|
||||
<field name="state">draft</field>
|
||||
<field name="case_default" eval="False"/>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_specification" model="project.task.type">
|
||||
<field name="sequence">2</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="name">Specification</field>
|
||||
<field name="state">pending</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_design" model="project.task.type">
|
||||
<field name="sequence">2</field>
|
||||
<field name="sequence">11</field>
|
||||
<field name="name">Design</field>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_development" model="project.task.type">
|
||||
<field name="sequence">3</field>
|
||||
<field name="sequence">12</field>
|
||||
<field name="name">Development</field>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_testing" model="project.task.type">
|
||||
<field name="sequence">4</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="name">Testing</field>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_merge" model="project.task.type">
|
||||
<field name="sequence">5</field>
|
||||
<field name="sequence">14</field>
|
||||
<field name="name">Merge</field>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="False"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_deployment" model="project.task.type">
|
||||
<field name="sequence">100</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="name">Done</field>
|
||||
<field name="state">done</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_cancel" model="project.task.type">
|
||||
<field name="sequence">200</field>
|
||||
<field name="sequence">30</field>
|
||||
<field name="name">Cancelled</field>
|
||||
<field name="state">cancelled</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
|
@ -86,11 +78,11 @@
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Task created</field>
|
||||
</record>
|
||||
<record id="mt_task_started" model="mail.message.subtype">
|
||||
<field name="name">Task Started</field>
|
||||
<record id="mt_task_assigned" model="mail.message.subtype">
|
||||
<field name="name">Task Assigned</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Task started</field>
|
||||
<field name="description">Task Assigned</field>
|
||||
</record>
|
||||
<record id="mt_task_blocked" model="mail.message.subtype">
|
||||
<field name="name">Task Blocked</field>
|
||||
|
@ -98,12 +90,6 @@
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Task blocked</field>
|
||||
</record>
|
||||
<record id="mt_task_closed" model="mail.message.subtype">
|
||||
<field name="name">Task Done</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Task closed</field>
|
||||
</record>
|
||||
<record id="mt_task_stage" model="mail.message.subtype">
|
||||
<field name="name">Stage Changed</field>
|
||||
<field name="res_model">project.task</field>
|
||||
|
@ -118,11 +104,11 @@
|
|||
<field name="parent_id" eval="ref('mt_task_new')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_task_started" model="mail.message.subtype">
|
||||
<field name="name">Task Started</field>
|
||||
<record id="mt_project_task_assigned" model="mail.message.subtype">
|
||||
<field name="name">Task Assigned</field>
|
||||
<field name="res_model">project.project</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="parent_id" eval="ref('mt_task_started')"/>
|
||||
<field name="parent_id" eval="ref('mt_task_assigned')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_task_blocked" model="mail.message.subtype">
|
||||
|
@ -131,12 +117,6 @@
|
|||
<field name="parent_id" eval="ref('mt_task_blocked')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_task_closed" model="mail.message.subtype">
|
||||
<field name="name">Task Done</field>
|
||||
<field name="res_model">project.project</field>
|
||||
<field name="parent_id" eval="ref('mt_task_closed')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_task_stage" model="mail.message.subtype">
|
||||
<field name="name">Task Stage Changed</field>
|
||||
<field name="res_model">project.project</field>
|
||||
|
|
|
@ -225,7 +225,6 @@
|
|||
ref('project.project_category_04')])]"/>
|
||||
<field name="stage_id" ref="project_tt_merge"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_close" eval="[ref('project_task_11')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_12" model="project.task">
|
||||
<field name="planned_hours" eval="40.0"/>
|
||||
|
@ -237,7 +236,6 @@
|
|||
<field name="stage_id" ref="project_tt_merge"/>
|
||||
<field name="color">6</field>
|
||||
</record>
|
||||
<function model="project.task" name="do_close" eval="[ref('project_task_12')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_13" model="project.task">
|
||||
<field name="planned_hours" eval="12.0"/>
|
||||
|
@ -248,7 +246,6 @@
|
|||
<field name="name">Design Use Cases</field>
|
||||
<field name="stage_id" ref="project_tt_analysis"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_pending" eval="[ref('project_task_13')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_14" model="project.task">
|
||||
<field name="planned_hours" eval="12.0"/>
|
||||
|
@ -282,7 +279,6 @@
|
|||
<field name="name">Set target for all deparments</field>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_16')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_17" model="project.task">
|
||||
<field name="planned_hours" eval="34.0"/>
|
||||
|
@ -293,7 +289,6 @@
|
|||
<field name="name">Integration of core components</field>
|
||||
<field name="stage_id" ref="project_tt_testing"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_17')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_18" model="project.task">
|
||||
<field name="planned_hours" eval="16.0"/>
|
||||
|
@ -315,7 +310,6 @@
|
|||
<field name="categ_ids" eval="[(6, 0, [
|
||||
ref('project_category_03')])]"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_19')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_20" model="project.task">
|
||||
<field name="planned_hours">42.0</field>
|
||||
|
@ -325,7 +319,6 @@
|
|||
<field name="project_id" ref="project.project_project_4"/>
|
||||
<field name="name">Create new components</field>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_20')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_21" model="project.task">
|
||||
<field name="planned_hours">14.0</field>
|
||||
|
@ -337,7 +330,6 @@
|
|||
<field name="categ_ids" eval="[(6, 0, [
|
||||
ref('project_category_04')])]"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_21')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_22" model="project.task">
|
||||
<field name="planned_hours">12.0</field>
|
||||
|
@ -371,7 +363,6 @@
|
|||
<field name="categ_ids" eval="[(6, 0, [
|
||||
ref('project_category_01')])]"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_24')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_25" model="project.task">
|
||||
<field name="sequence">20</field>
|
||||
|
@ -382,7 +373,6 @@
|
|||
<field name="name">Data importation + Doc</field>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_25')], {'install_mode': True}"/>
|
||||
|
||||
<record id="project_task_26" model="project.task">
|
||||
<field name="sequence">20</field>
|
||||
|
|
|
@ -18,29 +18,26 @@
|
|||
<search string="Tasks">
|
||||
<field name="name" string="Tasks"/>
|
||||
<field name="categ_ids"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<filter string="My Tasks" domain="[('user_id','=',uid)]"/>
|
||||
<separator/>
|
||||
<filter name="draft" string="New" domain="[('state','=','draft')]" help="New Tasks" icon="terp-check"/>
|
||||
<filter name="open" string="In Progress" domain="[('state','=','open')]" help="In Progress Tasks" icon="terp-camera_test"/>
|
||||
<filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/>
|
||||
<separator/>
|
||||
<filter name="My project" string="Project" domain="[('project_id.user_id','=',uid)]" help="My Projects" icon="terp-check"/>
|
||||
<separator/>
|
||||
<filter string="My Tasks" domain="[('user_id','=',uid)]" help="My Tasks" icon="terp-personal"/>
|
||||
<filter string="Unassigned Tasks" domain="[('user_id','=',False)]" help="Unassigned Tasks" icon="terp-personal-"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Deadlines" context="{'deadline_visible': False}" domain="[('date_deadline','<>',False)]"
|
||||
help="Show only tasks having a deadline" icon="terp-gnome-cpu-frequency-applet+"/>
|
||||
help="Show only tasks having a deadline"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="project_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Users" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Last Stage Update" icon="terp-go-month" domain="[]" context="{'group_by':'date_last_stage_update'}"/>
|
||||
<filter string="Deadline" icon="terp-gnome-cpu-frequency-applet+" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||
<filter string="Start Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_start'}" groups="base.group_no_one"/>
|
||||
<filter string="Start Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_start'}"/>
|
||||
<filter string="End Date" icon="terp-go-month" domain="[]" context="{'group_by':'date_end'}" groups="base.group_no_one"/>
|
||||
</group>
|
||||
</search>
|
||||
|
@ -371,18 +368,6 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Project" version="7.0">
|
||||
<header>
|
||||
<!--
|
||||
<button name="do_open" string="Start Task" type="object"
|
||||
states="draft,pending" class="oe_highlight"/>
|
||||
<button name="do_draft" string="Draft" type="object"
|
||||
states="cancel,done"/>
|
||||
-->
|
||||
<button name="project_task_reevaluate" string="Reactivate" type="object"
|
||||
states="cancelled,done" context="{'button_reactivate':True}" groups="base.group_user"/>
|
||||
<button name="action_close" string="Done" type="object"
|
||||
states="draft,open,pending" groups="base.group_user"/>
|
||||
<button name="do_cancel" string="Cancel Task" type="object"
|
||||
states="draft,open,pending" groups="base.group_user"/>
|
||||
<field name="stage_id" widget="statusbar" clickable="True"/>
|
||||
</header>
|
||||
<sheet string="Task">
|
||||
|
@ -396,8 +381,7 @@
|
|||
<group>
|
||||
<group>
|
||||
<field name="project_id" on_change="onchange_project(project_id)" context="{'default_use_tasks':1}"/>
|
||||
<field name="user_id"
|
||||
attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"
|
||||
<field name="user_id"
|
||||
options='{"no_open": True}'
|
||||
context="{'default_groups_ref': ['base.group_user', 'project.group_project_user']}"/>
|
||||
<field name="planned_hours" widget="float_time"
|
||||
|
@ -405,15 +389,15 @@
|
|||
on_change="onchange_planned(planned_hours, effective_hours)"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="categ_ids" widget="many2many_tags"/>
|
||||
<field name="progress" widget="progressbar"
|
||||
groups="project.group_time_work_estimation_tasks" attrs="{'invisible':[('state','=','cancelled')]}"/>
|
||||
groups="project.group_time_work_estimation_tasks"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Description">
|
||||
<field name="description" attrs="{'readonly':[('state','=','done')]}" placeholder="Add a Description..."/>
|
||||
<field name="description" placeholder="Add a Description..."/>
|
||||
<field name="work_ids" groups="project.group_tasks_work_on_tasks">
|
||||
<tree string="Task Work" editable="top">
|
||||
<field name="name"/>
|
||||
|
@ -427,7 +411,7 @@
|
|||
<field name="effective_hours" widget="float_time"/>
|
||||
<label for="remaining_hours" string="Remaining" groups="project.group_time_work_estimation_tasks"/>
|
||||
<div>
|
||||
<field name="remaining_hours" widget="float_time" attrs="{'readonly':[('state','in',('done','cancelled'))]}" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="remaining_hours" widget="float_time" groups="project.group_time_work_estimation_tasks"/>
|
||||
</div>
|
||||
<field name="total_hours" widget="float_time" class="oe_subtotal_footer_separator"/>
|
||||
</group>
|
||||
|
@ -436,7 +420,7 @@
|
|||
</page>
|
||||
<page string="Delegation" groups="project.group_delegate_task">
|
||||
<button name="%(action_project_task_delegate)d" string="Delegate" type="action"
|
||||
states="pending,open,draft" groups="project.group_delegate_task"/>
|
||||
groups="project.group_delegate_task"/>
|
||||
<separator string="Parent Tasks"/>
|
||||
<field name="parent_ids"/>
|
||||
<separator string="Delegated tasks"/>
|
||||
|
@ -445,7 +429,6 @@
|
|||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="remaining_hours" widget="float_time"/>
|
||||
|
@ -453,12 +436,11 @@
|
|||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Extra Info" attrs="{'readonly':[('state','=','done')]}">
|
||||
<page string="Extra Info">
|
||||
<group col="4">
|
||||
<field name="priority" groups="base.group_user"/>
|
||||
<field name="sequence"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
|
||||
</group>
|
||||
<group>
|
||||
|
@ -467,6 +449,7 @@
|
|||
<field name="date_end"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_last_stage_update" groups="base.group_no_one"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
@ -493,7 +476,6 @@
|
|||
<field name="user_email"/>
|
||||
<field name="description"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="kanban_state"/>
|
||||
<field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="date_deadline"/>
|
||||
|
@ -513,7 +495,6 @@
|
|||
<li><a name="set_remaining_time_2" type="object" class="oe_kanban_button">2</a></li>
|
||||
<li><a name="set_remaining_time_5" type="object" class="oe_kanban_button">5</a></li>
|
||||
<li><a name="set_remaining_time_10" type="object" class="oe_kanban_button">10</a></li>
|
||||
<li><a name="do_open" states="draft" string="Validate planned time" type="object" class="oe_kanban_button oe_kanban_button_active">!</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<br/>
|
||||
|
@ -562,7 +543,7 @@
|
|||
<field name="model">project.task</field>
|
||||
<field eval="2" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree fonts="bold:message_unread==True" colors="grey:state in ('cancelled','done');blue:state == 'pending';red:date_deadline and (date_deadline<current_date) and (state in ('draft','pending','open'))" string="Tasks">
|
||||
<tree fonts="bold:message_unread==True" colors="red:date_deadline and (date_deadline<current_date)" string="Tasks">
|
||||
<field name="message_unread" invisible="1"/>
|
||||
<field name="sequence" invisible="not context.get('seq_visible', False)"/>
|
||||
<field name="name"/>
|
||||
|
@ -575,7 +556,6 @@
|
|||
<field name="remaining_hours" widget="float_time" sum="Remaining Hours" on_change="onchange_remaining(remaining_hours,planned_hours)" invisible="context.get('set_visible',False)" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="date_deadline" invisible="context.get('deadline_visible',True)"/>
|
||||
<field name="stage_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="date_start" groups="base.group_no_one"/>
|
||||
<field name="date_end" groups="base.group_no_one"/>
|
||||
<field name="progress" widget="progressbar" invisible="context.get('set_visible',False)"/>
|
||||
|
@ -661,7 +641,7 @@
|
|||
<field name="res_model">project.task</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,calendar,graph,kanban</field>
|
||||
<field name="domain">[('date_deadline','<',time.strftime('%Y-%m-%d')),('state','in',('draft','pending','open'))]</field>
|
||||
<field name="domain">[('date_deadline','<',time.strftime('%Y-%m-%d'))]</field>
|
||||
<field name="filter" eval="True"/>
|
||||
<field name="search_view_id" ref="view_task_search_form"/>
|
||||
</record>
|
||||
|
@ -706,7 +686,6 @@
|
|||
<field name="case_default"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="state"/>
|
||||
<field name="sequence"/>
|
||||
<field name="fold"/>
|
||||
</group>
|
||||
|
@ -723,7 +702,7 @@
|
|||
<tree string="Task Stage">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
<field name="fold"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -767,7 +746,9 @@
|
|||
</record>
|
||||
|
||||
<!-- User Form -->
|
||||
<act_window context="{'search_default_user_id': [active_id], 'default_user_id': active_id}" domain="[('state', '<>', 'cancelled'),('state', '<>', 'done')]" id="act_res_users_2_project_task_opened" name="Assigned Tasks" res_model="project.task" src_model="res.users" view_mode="tree,form,gantt,calendar,graph" view_type="form"/>
|
||||
<act_window context="{'search_default_user_id': [active_id], 'default_user_id': active_id}"
|
||||
id="act_res_users_2_project_task_opened" name="Assigned Tasks"
|
||||
res_model="project.task" src_model="res.users" view_mode="tree,form,gantt,calendar,graph" view_type="form"/>
|
||||
|
||||
<!-- Tags -->
|
||||
<record model="ir.ui.view" id="project_category_search_view">
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<field name="user_id"/>
|
||||
<field name="remaining_hours"/>
|
||||
<field name="kanban_state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -40,8 +39,7 @@
|
|||
<field name="date"/>
|
||||
<field name="project_id"/>
|
||||
<field name="user_id"/>
|
||||
<filter name="open" string="In Progress Tasks" domain="[('state','in',('open','draft'))]"/>
|
||||
<filter string="Pending Tasks" domain="[('state','=','pending')]" context="{'show_delegated':False}"/>
|
||||
<filter name="new" string="New" domain="[('type_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter name="kanban_blocked" string="Blocked" domain="[('kanban_state','=','blocked')]"/>
|
||||
<filter name="kanban_ready" string="Ready" domain="[('kanban_state','=','done')]"/>
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import tools
|
||||
|
||||
|
||||
class report_project_task_user(osv.osv):
|
||||
_name = "report.project.task.user"
|
||||
_description = "Tasks by user and project"
|
||||
|
@ -31,10 +32,11 @@ class report_project_task_user(osv.osv):
|
|||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'year': fields.char('Year', size=64, required=False, readonly=True),
|
||||
'user_id': fields.many2one('res.users', 'Assigned To', readonly=True),
|
||||
'date_start': fields.date('Starting Date',readonly=True),
|
||||
'date_start': fields.date('Assignation Date', readonly=True),
|
||||
'no_of_days': fields.integer('# of Days', size=128, readonly=True),
|
||||
'date_end': fields.date('Ending Date', readonly=True),
|
||||
'date_deadline': fields.date('Deadline', readonly=True),
|
||||
'date_last_stage_update': fields.date('Last Stage Update', readonly=True),
|
||||
'project_id': fields.many2one('project.project', 'Project', readonly=True),
|
||||
'hours_planned': fields.float('Planned Hours', readonly=True),
|
||||
'hours_effective': fields.float('Effective Hours', readonly=True),
|
||||
|
@ -44,16 +46,17 @@ class report_project_task_user(osv.osv):
|
|||
'total_hours': fields.float('Total Hours', readonly=True),
|
||||
'closing_days': fields.float('Days to Close', digits=(16,2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to close the task"),
|
||||
'opening_days': fields.float('Days to Open', digits=(16,2), readonly=True, group_operator="avg",
|
||||
'opening_days': fields.float('Days to Assign', digits=(16,2), readonly=True, group_operator="avg",
|
||||
help="Number of Days to Open the task"),
|
||||
'delay_endings_days': fields.float('Overpassed Deadline', digits=(16,2), readonly=True),
|
||||
'nbr': fields.integer('# of tasks', readonly=True),
|
||||
'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'),
|
||||
('0','Very urgent')], 'Priority', readonly=True),
|
||||
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
|
||||
'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), ('1', 'Urgent'), ('0', 'Very urgent')],
|
||||
string='Priority', readonly=True),
|
||||
'month':fields.selection(fields.date.MONTHS, 'Month', readonly=True),
|
||||
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')],'Status', readonly=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Contact', readonly=True),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage'),
|
||||
}
|
||||
_order = 'name desc, project_id'
|
||||
|
||||
|
@ -69,19 +72,19 @@ class report_project_task_user(osv.osv):
|
|||
to_char(date_start, 'YYYY-MM-DD') as day,
|
||||
date_trunc('day',t.date_start) as date_start,
|
||||
date_trunc('day',t.date_end) as date_end,
|
||||
date_trunc('day',t.date_last_stage_update) as date_last_stage_update,
|
||||
to_date(to_char(t.date_deadline, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_deadline,
|
||||
-- sum(cast(to_char(date_trunc('day',t.date_end) - date_trunc('day',t.date_start),'DD') as int)) as no_of_days,
|
||||
abs((extract('epoch' from (t.date_end-t.date_start)))/(3600*24)) as no_of_days,
|
||||
t.user_id,
|
||||
progress as progress,
|
||||
t.project_id,
|
||||
t.state,
|
||||
t.effective_hours as hours_effective,
|
||||
t.priority,
|
||||
t.name as name,
|
||||
t.company_id,
|
||||
t.partner_id,
|
||||
t.stage_id,
|
||||
t.stage_id as stage_id,
|
||||
remaining_hours as remaining_hours,
|
||||
total_hours as total_hours,
|
||||
t.delay_hours as hours_delay,
|
||||
|
@ -106,15 +109,12 @@ class report_project_task_user(osv.osv):
|
|||
date_start,
|
||||
date_end,
|
||||
date_deadline,
|
||||
date_last_stage_update,
|
||||
t.user_id,
|
||||
t.project_id,
|
||||
t.state,
|
||||
t.priority,
|
||||
name,
|
||||
t.company_id,
|
||||
t.partner_id,
|
||||
t.stage_id
|
||||
|
||||
stage_id
|
||||
""")
|
||||
|
||||
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
<tree string="Tasks Analysis" create="false">
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="project_id" invisible="1"/>
|
||||
<field name="stage_id" invisible="1"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="date_start" invisible="1"/>
|
||||
<field name="date_end" invisible="1"/>
|
||||
<field name="date_last_stage_update" invisible="1"/>
|
||||
<field name="company_id" invisible="1" groups="base.group_multi_company"/>
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="day" invisible="1"/>
|
||||
|
@ -44,7 +45,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<graph string="Tasks Analysis" type="bar">
|
||||
<field name="name"/>
|
||||
<field name="state" group="True"/>
|
||||
<field name="stage_id" group="True"/>
|
||||
<field name="no_of_days" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
|
@ -58,31 +59,29 @@
|
|||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="date_deadline"/>
|
||||
<filter string="New" icon="terp-document-new" domain="[('state','=','draft')]" help = "New tasks"/>
|
||||
<filter string="In progress" icon="terp-check" domain="[('state', '=' ,'open')]" help = "In progress tasks"/>
|
||||
<filter string="Pending" icon="terp-gtk-media-pause" domain="[('state','=','pending')]" help = "Pending tasks"/>
|
||||
<filter string="Done" icon="terp-dialog-close" name="done" domain="[('state','=','done')]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-folder-violet" string="My Projects" help="My Projects" domain="[('project_id.user_id','=',uid)]"/>
|
||||
<separator/>
|
||||
<filter icon="terp-personal" string="My Task" help = "My tasks" domain="[('user_id','=',uid)]" />
|
||||
<filter icon="terp-personal-" string="Non Assigned Tasks to users" help="Non Assigned Tasks to users" domain="[('user_id','=',False)]"/>
|
||||
<field name="date_last_stage_update"/>
|
||||
<field name="project_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="stage_id"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter string="My Task" domain="[('user_id','=',uid)]" />
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="priority"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By...">
|
||||
<filter string="Project" name="project" icon="terp-folder-violet" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Task" icon="terp-stock_align_left_24" context="{'group_by':'name'}" />
|
||||
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
|
||||
<filter string="Assigned to" name="User" icon="terp-personal" context="{'group_by':'user_id'}" />
|
||||
<filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Day" icon="terp-go-today" context="{'group_by':'day'}" help="Creation Date"/>
|
||||
<filter string="Month" icon="terp-go-month" context="{'group_by':'month'}" help="Creation Date"/>
|
||||
<filter string="Year" icon="terp-go-year" context="{'group_by':'year'}" help="Creation Date"/>
|
||||
<filter string="Project" name="project" context="{'group_by':'project_id'}"/>
|
||||
<filter string="Task" context="{'group_by':'name'}" />
|
||||
<filter string="Contact" context="{'group_by':'partner_id'}" />
|
||||
<filter string="Assigned to" name="User" context="{'group_by':'user_id'}" />
|
||||
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Day" context="{'group_by':'day'}" help="Creation Date"/>
|
||||
<filter string="Month" context="{'group_by':'month'}" help="Creation Date"/>
|
||||
<filter string="Year" context="{'group_by':'year'}" help="Creation Date"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}" help="Last Stage Update"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
|
|
@ -19,6 +19,7 @@ access_project_task_history,project.task.history project,project.model_project_t
|
|||
access_project_task_history_cumulative,project.task.history project,project.model_project_task_history_cumulative,project.group_project_manager,1,0,0,0
|
||||
access_project_task_history_cumulative,project.task.history project,project.model_project_task_history_cumulative,project.group_project_user,1,0,0,0
|
||||
access_resource_calendar,project.resource_calendar manager,resource.model_resource_calendar,project.group_project_manager,1,0,0,0
|
||||
access_resource_calendar_leaves_user,resource.calendar.leaves user,resource.model_resource_calendar_leaves,project.group_project_user,1,1,1,1
|
||||
access_project_category,project.project_category,model_project_category,,1,0,0,0
|
||||
access_project_category_manager,project.project_category,model_project_category,project.group_project_manager,1,1,1,1
|
||||
access_mail_alias,mail.alias,mail.model_mail_alias,project.group_project_manager,1,1,1,1
|
||||
|
|
|
|
@ -17,7 +17,7 @@ work done. Keep track of everything, from the big picture to the minute
|
|||
details, from the customer contract to the billing.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=project" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
-
|
||||
!record {model: project.project, id: project_project_1, view: False}:
|
||||
partner_id: base.res_partner_2
|
||||
-
|
||||
!record {model: project.task, id: project_task_1, view: False}:
|
||||
remaining_hours: 10.00
|
||||
-
|
||||
!record {model: project.task, id: project_task_1, view: False}:
|
||||
planned_hours: 10.00
|
||||
-
|
||||
!record {model: project.task, id: project_task_1, view: False}:
|
||||
project_id: project_project_1
|
|
@ -1,70 +0,0 @@
|
|||
-
|
||||
In order to Test Process of Project Management,
|
||||
-
|
||||
I create duplicate template.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
new_template = self.duplicate_template(cr, uid, [ref("project_project_1")])
|
||||
assert new_template, "duplicate template is not created"
|
||||
template = self.browse(cr, uid, new_template['res_id'], context=context)
|
||||
assert template.state == 'open', "Duplicate template must be in open state."
|
||||
-
|
||||
I convert template into real Project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.reset_project(cr, uid, [ref("project_project_1")])
|
||||
-
|
||||
I check project details after convert from template.
|
||||
-
|
||||
!assert {model: project.project, id: project_project_1, severity: error, string: Project should be active}:
|
||||
- state == "open"
|
||||
-
|
||||
I put project in pending.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.set_pending(cr, uid, [ref("project_project_1")])
|
||||
-
|
||||
I check state after put in pending.
|
||||
-
|
||||
!assert {model: project.project, id: project_project_1, severity: error, string: Project should be in pending state}:
|
||||
- state == "pending"
|
||||
-
|
||||
I re-open the project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.set_open(cr, uid, [ref("project_project_1")])
|
||||
-
|
||||
I check state after reopen.
|
||||
-
|
||||
!assert {model: project.project, id: project_project_1, severity: error, string: Project should be open.}:
|
||||
- state == "open"
|
||||
-
|
||||
I close the project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.set_done(cr, uid, [ref("project_project_1")])
|
||||
-
|
||||
I check state after closed.
|
||||
-
|
||||
!assert {model: project.project, id: project_project_1, severity: error, string: Project should be close.}:
|
||||
- state == "close"
|
||||
-
|
||||
I set project into template.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.set_template(cr, uid, [ref("project_project_1")])
|
||||
-
|
||||
I schedule tasks of project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.schedule_tasks(cr, uid, [ref("project_project_1")], context=context)
|
||||
-
|
||||
I copy the tasks of project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.copy(cr, uid, ref("project_project_1"))
|
||||
-
|
||||
I cancel Project.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.set_cancel(cr, uid, [ref("project_project_2")])
|
|
@ -1,76 +0,0 @@
|
|||
-
|
||||
I put task in pending due to specification is not clear.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.do_pending(cr, uid, [ref("project_task_1")])
|
||||
context.update({"active_id": ref("project_task_1")})
|
||||
-
|
||||
I check state of task after put in pending.
|
||||
-
|
||||
!assert {model: project.task, id: project_task_1, severity: error, string: task should be in pending state}:
|
||||
- state == "pending"
|
||||
-
|
||||
!record {model: project.task.delegate, id: delegate_id}:
|
||||
user_id: base.user_demo
|
||||
planned_hours: 12.0
|
||||
planned_hours_me: 2.0
|
||||
-
|
||||
Now I delegate task to team member.
|
||||
-
|
||||
!python {model: project.task.delegate}: |
|
||||
self.delegate(cr, uid, [ref("delegate_id")], {"active_id": ref("project_task_1")})
|
||||
-
|
||||
I check delegated task details.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
task = self.browse(cr, uid, ref("project_task_1"), context=context)
|
||||
assert task.planned_hours == 2.0, "Planning hours is not correct after delegated."
|
||||
assert task.state == "pending", "Task should be in Pending after delegated."
|
||||
-
|
||||
I re-open the task.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.do_reopen(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
I check reopened task details.
|
||||
-
|
||||
!assert {model: project.task, id: project_task_1, severity: error, string: task should be open.}:
|
||||
- state == "open"
|
||||
-
|
||||
I change the stage of task to next stage.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.stage_next(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
!record {model: project.task.reevaluate, id: reevaluate_id}:
|
||||
remaining_hours : 120
|
||||
-
|
||||
I reevaluate task with remaining hours.
|
||||
-
|
||||
!python {model: project.task.reevaluate}: |
|
||||
self.compute_hours(cr, uid, [ref("reevaluate_id")], {"active_id": ref("project_task_1")})
|
||||
-
|
||||
I check remaining hours after reevaluated task.
|
||||
-
|
||||
!assert {model: project.task, id: project_task_1, severity: error, string: task should be reevaluated}:
|
||||
- remaining_hours == 120.0
|
||||
-
|
||||
I close the task.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.action_close(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
I check state after closed.
|
||||
-
|
||||
!assert {model: project.task, id: project_task_1, severity: error, string: task is in open state}:
|
||||
- state == "done"
|
||||
-
|
||||
I change the stage of task to previous stage.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.stage_previous(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
I cancel Task.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.do_cancel(cr, uid, [ref("project_task_2")])
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import test_project_flow
|
||||
|
||||
checks = [
|
||||
test_project_flow,
|
||||
]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,99 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.mail.tests.test_mail_base import TestMailBase
|
||||
|
||||
|
||||
class TestProjectBase(TestMailBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestProjectBase, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Usefull models
|
||||
self.project_project = self.registry('project.project')
|
||||
self.project_task = self.registry('project.task')
|
||||
self.project_task_delegate = self.registry('project.task.delegate')
|
||||
|
||||
# Find Project User group
|
||||
group_project_user_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_user')
|
||||
self.group_project_user_id = group_project_user_ref and group_project_user_ref[1] or False
|
||||
|
||||
# Find Project Manager group
|
||||
group_project_manager_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'project', 'group_project_manager')
|
||||
self.group_project_manager_id = group_project_manager_ref and group_project_manager_ref[1] or False
|
||||
|
||||
# Test partners to use through the various tests
|
||||
self.project_partner_id = self.res_partner.create(cr, uid, {
|
||||
'name': 'Gertrude AgrolaitPartner',
|
||||
'email': 'gertrude.partner@agrolait.com',
|
||||
})
|
||||
self.email_partner_id = self.res_partner.create(cr, uid, {
|
||||
'name': 'Patrick Ratatouille',
|
||||
'email': 'patrick.ratatouille@agrolait.com',
|
||||
})
|
||||
|
||||
# Test users to use through the various tests
|
||||
self.user_projectuser_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Armande ProjectUser',
|
||||
'login': 'Armande',
|
||||
'alias_name': 'armande',
|
||||
'email': 'armande.projectuser@example.com',
|
||||
'groups_id': [(6, 0, [self.group_employee_id, self.group_project_user_id])]
|
||||
})
|
||||
self.user_projectmanager_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Bastien ProjectManager',
|
||||
'login': 'bastien',
|
||||
'alias_name': 'bastien',
|
||||
'email': 'bastien.projectmanager@example.com',
|
||||
'groups_id': [(6, 0, [self.group_employee_id, self.group_project_manager_id])]
|
||||
})
|
||||
self.user_none_id = self.res_users.create(cr, uid, {
|
||||
'name': 'Charlie Avotbonkeur',
|
||||
'login': 'charlie',
|
||||
'alias_name': 'charlie',
|
||||
'email': 'charlie.noone@example.com',
|
||||
'groups_id': [(6, 0, [])]
|
||||
})
|
||||
self.user_projectuser = self.res_users.browse(cr, uid, self.user_projectuser_id)
|
||||
self.user_projectmanager = self.res_users.browse(cr, uid, self.user_projectmanager_id)
|
||||
self.partner_projectuser_id = self.user_projectuser.partner_id.id
|
||||
self.partner_projectmanager_id = self.user_projectmanager.partner_id.id
|
||||
|
||||
# Test 'Pigs' project
|
||||
self.project_pigs_id = self.project_project.create(cr, uid, {
|
||||
'name': 'Pigs',
|
||||
'privacy_visibility': 'public',
|
||||
'alias_name': 'project+pigs',
|
||||
'partner_id': self.partner_raoul_id,
|
||||
}, {'mail_create_nolog': True})
|
||||
|
||||
# Already-existing tasks in Pigs
|
||||
self.task_1_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Pigs UserTask',
|
||||
'user_id': self.user_projectuser_id,
|
||||
'project_id': self.project_pigs_id,
|
||||
}, {'mail_create_nolog': True})
|
||||
self.task_2_id = self.project_task.create(cr, uid, {
|
||||
'name': 'Pigs ManagerTask',
|
||||
'user_id': self.user_projectmanager_id,
|
||||
'project_id': self.project_pigs_id,
|
||||
}, {'mail_create_nolog': True})
|
|
@ -0,0 +1,163 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.project.tests.test_project_base import TestProjectBase
|
||||
from openerp.osv.orm import except_orm
|
||||
from openerp.tools import mute_logger
|
||||
|
||||
|
||||
EMAIL_TPL = """Return-Path: <whatever-2a840@postmaster.twitter.com>
|
||||
X-Original-To: {email_to}
|
||||
Delivered-To: {email_to}
|
||||
To: {email_to}
|
||||
Received: by mail1.openerp.com (Postfix, from userid 10002)
|
||||
id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
|
||||
Message-ID: {msg_id}
|
||||
Date: Tue, 29 Nov 2011 12:43:21 +0530
|
||||
From: {email_from}
|
||||
MIME-Version: 1.0
|
||||
Subject: {subject}
|
||||
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||
|
||||
Hello,
|
||||
|
||||
This email should create a new entry in your module. Please check that it
|
||||
effectively works.
|
||||
|
||||
Thanks,
|
||||
|
||||
--
|
||||
Raoul Boitempoils
|
||||
Integrator at Agrolait"""
|
||||
|
||||
|
||||
class TestProjectFlow(TestProjectBase):
|
||||
|
||||
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.osv.orm')
|
||||
def test_00_project_process(self):
|
||||
""" Testing project management """
|
||||
cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id
|
||||
|
||||
# ProjectUser: set project as template -> raise
|
||||
self.assertRaises(except_orm, self.project_project.set_template, cr, user_projectuser_id, [project_pigs_id])
|
||||
|
||||
# Other tests are done using a ProjectManager
|
||||
project = self.project_project.browse(cr, user_projectmanager_id, project_pigs_id)
|
||||
self.assertNotEqual(project.state, 'template', 'project: incorrect state, should not be a template')
|
||||
|
||||
# Set test project as template
|
||||
self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
self.assertEqual(project.state, 'template', 'project: set_template: project state should be template')
|
||||
self.assertEqual(len(project.tasks), 0, 'project: set_template: project tasks should have been set inactive')
|
||||
|
||||
# Duplicate template
|
||||
new_template_act = self.project_project.duplicate_template(cr, user_projectmanager_id, [project_pigs_id])
|
||||
new_project = self.project_project.browse(cr, user_projectmanager_id, new_template_act['res_id'])
|
||||
self.assertEqual(new_project.state, 'open', 'project: incorrect duplicate_template')
|
||||
self.assertEqual(len(new_project.tasks), 2, 'project: duplicating a project template should duplicate its tasks')
|
||||
|
||||
# Convert into real project
|
||||
self.project_project.reset_project(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
self.assertEqual(project.state, 'open', 'project: resetted project should be in open state')
|
||||
self.assertEqual(len(project.tasks), 2, 'project: reset_project: project tasks should have been set active')
|
||||
|
||||
# Put as pending
|
||||
self.project_project.set_pending(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
self.assertEqual(project.state, 'pending', 'project: should be in pending state')
|
||||
|
||||
# Re-open
|
||||
self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
self.assertEqual(project.state, 'open', 'project: reopened project should be in open state')
|
||||
|
||||
# Close project
|
||||
self.project_project.set_done(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
self.assertEqual(project.state, 'close', 'project: closed project should be in close state')
|
||||
|
||||
# Re-open
|
||||
self.project_project.set_open(cr, user_projectmanager_id, [project_pigs_id])
|
||||
project.refresh()
|
||||
|
||||
# Re-convert into a template and schedule tasks
|
||||
self.project_project.set_template(cr, user_projectmanager_id, [project_pigs_id])
|
||||
self.project_project.schedule_tasks(cr, user_projectmanager_id, [project_pigs_id])
|
||||
|
||||
# Copy the project
|
||||
new_project_id = self.project_project.copy(cr, user_projectmanager_id, project_pigs_id)
|
||||
new_project = self.project_project.browse(cr, user_projectmanager_id, new_project_id)
|
||||
self.assertEqual(len(new_project.tasks), 2, 'project: copied project should have copied task')
|
||||
|
||||
# Cancel the project
|
||||
self.project_project.set_cancel(cr, user_projectmanager_id, [project_pigs_id])
|
||||
self.assertEqual(project.state, 'cancelled', 'project: cancelled project should be in cancel state')
|
||||
|
||||
def test_10_task_process(self):
|
||||
""" Testing task creation and management """
|
||||
cr, uid, user_projectuser_id, user_projectmanager_id, project_pigs_id = self.cr, self.uid, self.user_projectuser_id, self.user_projectmanager_id, self.project_pigs_id
|
||||
|
||||
def format_and_process(template, email_to='project+pigs@mydomain.com, other@gmail.com', subject='Frogs',
|
||||
email_from='Patrick Ratatouille <patrick.ratatouille@agrolait.com>',
|
||||
msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>'):
|
||||
self.assertEqual(self.project_task.search(cr, uid, [('name', '=', subject)]), [])
|
||||
mail = template.format(email_to=email_to, subject=subject, email_from=email_from, msg_id=msg_id)
|
||||
self.mail_thread.message_process(cr, uid, None, mail)
|
||||
return self.project_task.search(cr, uid, [('name', '=', subject)])
|
||||
|
||||
# Do: incoming mail from an unknown partner on an alias creates a new task 'Frogs'
|
||||
frogs = format_and_process(EMAIL_TPL)
|
||||
|
||||
# Test: one task created by mailgateway administrator
|
||||
self.assertEqual(len(frogs), 1, 'project: message_process: a new project.task should have been created')
|
||||
task = self.project_task.browse(cr, user_projectuser_id, frogs[0])
|
||||
res = self.project_task.perm_read(cr, uid, [task.id], details=False)
|
||||
self.assertEqual(res[0].get('create_uid'), uid,
|
||||
'project: message_process: task should have been created by uid as alias_user_id is False on the alias')
|
||||
# Test: messages
|
||||
self.assertEqual(len(task.message_ids), 3,
|
||||
'project: message_process: newly created task should have 2 messages: creation and email')
|
||||
self.assertEqual(task.message_ids[2].subtype_id.name, 'Task Created',
|
||||
'project: message_process: first message of new task should have Task Created subtype')
|
||||
self.assertEqual(task.message_ids[1].subtype_id.name, 'Task Assigned',
|
||||
'project: message_process: first message of new task should have Task Created subtype')
|
||||
self.assertEqual(task.message_ids[0].author_id.id, self.email_partner_id,
|
||||
'project: message_process: second message should be the one from Agrolait (partner failed)')
|
||||
self.assertEqual(task.message_ids[0].subject, 'Frogs',
|
||||
'project: message_process: second message should be the one from Agrolait (subject failed)')
|
||||
# Test: task content
|
||||
self.assertEqual(task.name, 'Frogs', 'project_task: name should be the email subject')
|
||||
self.assertEqual(task.project_id.id, self.project_pigs_id, 'project_task: incorrect project')
|
||||
self.assertEqual(task.stage_id.sequence, 1, 'project_task: should have a stage with sequence=1')
|
||||
|
||||
# Open the delegation wizard
|
||||
delegate_id = self.project_task_delegate.create(cr, user_projectuser_id, {
|
||||
'user_id': user_projectuser_id,
|
||||
'planned_hours': 12.0,
|
||||
'planned_hours_me': 2.0,
|
||||
}, {'active_id': task.id})
|
||||
self.project_task_delegate.delegate(cr, user_projectuser_id, [delegate_id], {'active_id': task.id})
|
||||
|
||||
# Check delegation details
|
||||
task.refresh()
|
||||
self.assertEqual(task.planned_hours, 2, 'project_task_delegate: planned hours is not correct after delegation')
|
|
@ -20,7 +20,5 @@
|
|||
##############################################################################
|
||||
|
||||
import project_task_delegate
|
||||
import project_task_reevaluate
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from lxml import etree
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class project_task_reevaluate(osv.osv_memory):
|
||||
_name = 'project.task.reevaluate'
|
||||
|
||||
def _get_remaining(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
active_id = context.get('active_id', False)
|
||||
res = False
|
||||
if active_id:
|
||||
res = self.pool.get('project.task').browse(cr, uid, active_id, context=context).remaining_hours
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'remaining_hours' : fields.float('Remaining Hours', digits=(16,2), help="Put here the remaining hours required to close the task."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'remaining_hours': _get_remaining,
|
||||
}
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
|
||||
res = super(project_task_reevaluate, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu=submenu)
|
||||
users_pool = self.pool.get('res.users')
|
||||
time_mode = users_pool.browse(cr, uid, uid, context).company_id.project_time_mode_id
|
||||
time_mode_name = time_mode and time_mode.name or 'Hours'
|
||||
if time_mode_name in ['Hours','Hour']:
|
||||
return res
|
||||
|
||||
eview = etree.fromstring(res['arch'])
|
||||
|
||||
def _check_rec(eview):
|
||||
if eview.attrib.get('widget','') == 'float_time':
|
||||
eview.set('widget','float')
|
||||
for child in eview:
|
||||
_check_rec(child)
|
||||
return True
|
||||
|
||||
_check_rec(eview)
|
||||
|
||||
res['arch'] = etree.tostring(eview)
|
||||
|
||||
for field in res['fields']:
|
||||
if 'Hours' in res['fields'][field]['string']:
|
||||
res['fields'][field]['string'] = res['fields'][field]['string'].replace('Hours',time_mode_name)
|
||||
return res
|
||||
|
||||
def compute_hours(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
task_id = context.get('active_id')
|
||||
if task_id:
|
||||
task_pool = self.pool.get('project.task')
|
||||
task_pool.write(cr, uid, task_id, {'remaining_hours': data.remaining_hours})
|
||||
if context.get('button_reactivate'):
|
||||
task_pool.do_reopen(cr, uid, [task_id], context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_project_task_reevaluate" model="ir.ui.view">
|
||||
<field name="name">Re-evaluate Task</field>
|
||||
<field name="model">project.task.reevaluate</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Reevaluate Task" version="7.0">
|
||||
<separator string="Reevaluation Task"/>
|
||||
<group>
|
||||
<field name="remaining_hours" widget="float_time"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="compute_hours" string="_Evaluate" type="object" default_focus="1" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_task_reevaluate" model="ir.actions.act_window">
|
||||
<field name="name">Re-evaluate Task</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">project.task.reevaluate</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -79,7 +79,6 @@
|
|||
<field name="remaining_hours" position="after">
|
||||
<field string="Timeframe" name="timebox_id" invisible=" not context.get('gtd', False)"/>
|
||||
<field name="context_id" invisible="not context.get('context_show', False)" widget="selection"/>
|
||||
<button name="do_reopen" states="done,cancelled" string="Reactivate" type="object" icon="gtk-convert" help="For reopening the tasks" invisible="not context.get('set_visible',False)"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -103,16 +102,17 @@
|
|||
<field name="arch" type="xml">
|
||||
<search string="My Tasks">
|
||||
<field name="name" string="My Tasks"/>
|
||||
<filter name="open" string="In Progress" domain="[('state','in',('draft','open'))]" help="In Progress and draft tasks" icon="terp-camera_test"/>
|
||||
<filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter name="message_unread" string="Unread Messages" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Inbox" domain="[('timebox_id','=', False)]" help="Tasks having no timebox assigned yet"/>
|
||||
<filter string="No Timebox" domain="[('timebox_id', '=', False)]" help="Tasks having no timebox assigned yet"/>
|
||||
<group expand="0" string="Display">
|
||||
<filter string="Show Context" name="context_show" context="{'context_show': True}" domain="[]" icon="terp-camera_test" help="Show the context field"/>
|
||||
<filter string="Show Deadlines" context="{'deadline_visible': False}" domain="[]" help="Show only tasks having a deadline" icon="terp-gnome-cpu-frequency-applet+"/>
|
||||
</group>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Stage" name="group_stage_id" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Timebox" name="group_timebox_id" context="{'group_by':'timebox_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -52,7 +52,7 @@ class project_timebox_empty(osv.osv_memory):
|
|||
raise osv.except_osv(_('Error!'), _('No timebox child of this one!'))
|
||||
tids = obj_task.search(cr, uid, [('timebox_id', '=', context['active_id'])])
|
||||
for task in obj_task.browse(cr, uid, tids, context):
|
||||
if (task.state in ('cancel','done')) or (task.user_id.id <> uid):
|
||||
if (task.stage_id and task.stage_id.fold) or (task.user_id.id <> uid):
|
||||
close.append(task.id)
|
||||
else:
|
||||
up.append(task.id)
|
||||
|
|
|
@ -55,7 +55,6 @@ It allows the manager to quickly check the issues, assign them and decide on the
|
|||
'test': [
|
||||
'test/subscribe_issue.yml',
|
||||
'test/issue_process.yml',
|
||||
'test/cancel_issue.yml',
|
||||
'test/issue_demo.yml'
|
||||
],
|
||||
'installable': True,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<field name="name">Project Issue Board Tree</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Issue Tracker Tree" colors="black:state=='open';blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<tree string="Issue Tracker Tree">
|
||||
<field name="id"/>
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
|
@ -16,7 +16,6 @@
|
|||
<field name="version_id" widget="selection"/>
|
||||
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="categ_ids" invisible="1"/>
|
||||
<field name="task_id" invisible="1"/>
|
||||
</tree>
|
||||
|
@ -28,7 +27,7 @@
|
|||
<field name="res_model">project.issue</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state','not in',('cancel','done')),('user_id','=',uid)]</field>
|
||||
<field name="domain">[('user_id', '=', uid)]</field>
|
||||
<field name="view_id" ref="project_issue_board_tree_view"/>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
.. _changelog:
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
`trunk (saas-2)`
|
||||
----------------
|
||||
|
||||
- Stage/state update
|
||||
|
||||
- ``project.issue``: removed inheritance from ``base_stage`` class and removed
|
||||
``state`` field. Added ``date_last_stage_update`` field holding last stage_id
|
||||
modification. Updated reports.
|
|
@ -0,0 +1,22 @@
|
|||
=====================
|
||||
Project Issue DevDoc
|
||||
=====================
|
||||
|
||||
Project Issue module documentation
|
||||
===================================
|
||||
|
||||
Documentation topics
|
||||
''''''''''''''''''''
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
stage_status.rst
|
||||
|
||||
Changelog
|
||||
'''''''''
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
changelog.rst
|
|
@ -0,0 +1,54 @@
|
|||
.. _stage_status:
|
||||
|
||||
Stage and Status
|
||||
================
|
||||
|
||||
.. versionchanged:: 8.0 saas-2 state/stage cleaning
|
||||
|
||||
Stage
|
||||
+++++
|
||||
|
||||
This revision removed the concept of state on project.issue objects. The ``state``
|
||||
field has been totally removed and replaced by stages, using ``stage_id``. The
|
||||
following models are impacted:
|
||||
|
||||
- ``project.issue`` now use only stages. However a convention still exists about
|
||||
'New' stage. An issue is consdered as ``new`` when it has the following
|
||||
properties:
|
||||
|
||||
- ``stage_id and stage_id.sequence = 1``
|
||||
|
||||
- ``project.task.type`` do not have any ``state`` field anymore.
|
||||
- ``project.issue.report`` do not have any ``state`` field anymore.
|
||||
|
||||
By default a newly created issue is in a new stage. It means that it will
|
||||
fetch the stage having ``sequence = 1``. Stage mangement is done using the
|
||||
kanban view or the clikable statusbar. It is not done using buttons anymore.
|
||||
|
||||
Stage analysis
|
||||
++++++++++++++
|
||||
|
||||
Stage analysis can be performed using the newly introduced ``date_last_stage_update``
|
||||
datetime field. This field is updated everytime ``stage_id`` is updated.
|
||||
|
||||
``project.issue.report`` model also uses the ``date_last_stage_update`` field.
|
||||
This allows to group and analyse the time spend in the various stages.
|
||||
|
||||
Open / Assignation date
|
||||
+++++++++++++++++++++++
|
||||
|
||||
The ``date_open`` field meaning has been updated. It is now set when the ``user_id``
|
||||
(responsible) is set. It is therefore the assignation date.
|
||||
|
||||
Subtypes
|
||||
++++++++
|
||||
|
||||
The following subtypes are triggered on ``project.issue``:
|
||||
|
||||
- ``mt_issue_new``: new tasks. Condition: ``obj.stage_id and obj.stage_id.sequence == 1``
|
||||
- ``mt_issue_stage``: stage changed. Condition: ``obj.stage_id and obj.stage_id.sequence != 1``
|
||||
- ``mt_issue_assigned``: user assigned. condition: ``obj.user_id and obj.user_id.id``
|
||||
- ``mt_issue_blocked``: kanban state blocked. Condition: ``obj.kanban_state == 'blocked'``
|
||||
|
||||
Those subtypes are also available on the ``project.project`` model and are used
|
||||
for the auto subscription.
|
|
@ -19,19 +19,16 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.addons.base_status.base_stage import base_stage
|
||||
from openerp.addons.project.project import _TASK_STATE
|
||||
from openerp.addons.crm import crm
|
||||
from datetime import datetime
|
||||
from openerp.osv import fields, osv, orm
|
||||
from openerp.tools.translate import _
|
||||
import binascii
|
||||
import time
|
||||
from openerp import tools
|
||||
from openerp.tools import html2plaintext
|
||||
|
||||
class project_issue_version(osv.osv):
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp import tools
|
||||
from openerp.addons.crm import crm
|
||||
from openerp.osv import fields, osv, orm
|
||||
from openerp.tools import html2plaintext
|
||||
from openerp.tools.translate import _
|
||||
|
||||
class project_issue_version(osv.Model):
|
||||
_name = "project.issue.version"
|
||||
_order = "name desc"
|
||||
_columns = {
|
||||
|
@ -42,36 +39,25 @@ class project_issue_version(osv.osv):
|
|||
'active': 1,
|
||||
}
|
||||
|
||||
class project_issue(base_stage, osv.osv):
|
||||
class project_issue(osv.Model):
|
||||
_name = "project.issue"
|
||||
_description = "Project Issue"
|
||||
_order = "priority, create_date desc"
|
||||
_inherit = ['mail.thread', 'ir.needaction_mixin']
|
||||
|
||||
_track = {
|
||||
'state': {
|
||||
'project_issue.mt_issue_new': lambda self, cr, uid, obj, ctx=None: obj.state in ['new', 'draft'],
|
||||
'project_issue.mt_issue_closed': lambda self, cr, uid, obj, ctx=None: obj.state == 'done',
|
||||
'project_issue.mt_issue_started': lambda self, cr, uid, obj, ctx=None: obj.state == 'open',
|
||||
},
|
||||
'stage_id': {
|
||||
'project_issue.mt_issue_stage': lambda self, cr, uid, obj, ctx=None: obj.state not in ['new', 'draft', 'done', 'open'],
|
||||
'project_issue.mt_issue_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1,
|
||||
'project_issue.mt_issue_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence != 1,
|
||||
},
|
||||
'user_id': {
|
||||
'project_issue.mt_issue_assigned': lambda self, cr, uid, obj, ctx=None: obj.user_id and obj.user_id.id,
|
||||
},
|
||||
'kanban_state': {
|
||||
'project_issue.mt_issue_blocked': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'blocked',
|
||||
},
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if vals.get('project_id') and not context.get('default_project_id'):
|
||||
context['default_project_id'] = vals.get('project_id')
|
||||
|
||||
# context: no_log, because subtype already handle this
|
||||
create_context = dict(context, mail_create_nolog=True)
|
||||
return super(project_issue, self).create(cr, uid, vals, context=create_context)
|
||||
|
||||
def _get_default_partner(self, cr, uid, context=None):
|
||||
""" Override of base_stage to add project specific behavior """
|
||||
project_id = self._get_default_project_id(cr, uid, context)
|
||||
|
@ -79,7 +65,7 @@ class project_issue(base_stage, osv.osv):
|
|||
project = self.pool.get('project.project').browse(cr, uid, project_id, context=context)
|
||||
if project and project.partner_id:
|
||||
return project.partner_id.id
|
||||
return super(project_issue, self)._get_default_partner(cr, uid, context=context)
|
||||
return False
|
||||
|
||||
def _get_default_project_id(self, cr, uid, context=None):
|
||||
""" Gives default project by checking if present in the context """
|
||||
|
@ -88,7 +74,7 @@ class project_issue(base_stage, osv.osv):
|
|||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
""" Gives default stage_id """
|
||||
project_id = self._get_default_project_id(cr, uid, context=context)
|
||||
return self.stage_find(cr, uid, [], project_id, [('state', '=', 'draft')], context=context)
|
||||
return self.stage_find(cr, uid, [], project_id, [('sequence', '=', 1)], context=context)
|
||||
|
||||
def _resolve_project_id_from_context(self, cr, uid, context=None):
|
||||
""" Returns ID of project based on the value of 'default_project_id'
|
||||
|
@ -258,13 +244,6 @@ class project_issue(base_stage, osv.osv):
|
|||
'partner_id': fields.many2one('res.partner', 'Contact', select=1),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'description': fields.text('Private Note'),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=_TASK_STATE, string="Status", readonly=True,
|
||||
help='The status is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the status is set to \'Open\'.\
|
||||
When the case is over, the status is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the status is \
|
||||
set to \'Pending\'.'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready for next stage')], 'Kanban State',
|
||||
track_visibility='onchange',
|
||||
help="A Issue's kanban state indicates special situations affecting it:\n"
|
||||
|
@ -278,6 +257,7 @@ class project_issue(base_stage, osv.osv):
|
|||
# Project Issue fields
|
||||
'date_closed': fields.datetime('Closed', readonly=True,select=True),
|
||||
'date': fields.datetime('Date'),
|
||||
'date_last_stage_update': fields.datetime('Last Stage Update', select=True),
|
||||
'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel."),
|
||||
'categ_ids': fields.many2many('project.category', string='Tags'),
|
||||
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
|
||||
|
@ -313,13 +293,11 @@ class project_issue(base_stage, osv.osv):
|
|||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
|
||||
'priority': crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'kanban_state': 'normal',
|
||||
'date_last_stage_update': fields.datetime.now(),
|
||||
'user_id': lambda obj, cr, uid, context: uid,
|
||||
}
|
||||
|
||||
|
@ -373,7 +351,7 @@ class project_issue(base_stage, osv.osv):
|
|||
})
|
||||
vals = {
|
||||
'task_id': new_task_id,
|
||||
'stage_id': self.stage_find(cr, uid, [bug], bug.project_id.id, [('state', '=', 'pending')], context=context),
|
||||
'stage_id': self.stage_find(cr, uid, [bug], bug.project_id.id, [('sequence', '=', 1)], context=context),
|
||||
}
|
||||
message = _("Project issue <b>converted</b> to task.")
|
||||
self.message_post(cr, uid, [bug.id], body=message, context=context)
|
||||
|
@ -401,19 +379,23 @@ class project_issue(base_stage, osv.osv):
|
|||
return super(project_issue, self).copy(cr, uid, id, default=default,
|
||||
context=context)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if vals.get('project_id') and not context.get('default_project_id'):
|
||||
context['default_project_id'] = vals.get('project_id')
|
||||
|
||||
# context: no_log, because subtype already handle this
|
||||
create_context = dict(context, mail_create_nolog=True)
|
||||
return super(project_issue, self).create(cr, uid, vals, context=create_context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
|
||||
#Update last action date every time the user changes the stage
|
||||
# stage change: update date_last_stage_update
|
||||
if 'stage_id' in vals:
|
||||
vals['date_action_last'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
state = self.pool.get('project.task.type').browse(cr, uid, vals['stage_id'], context=context).state
|
||||
for issue in self.browse(cr, uid, ids, context=context):
|
||||
# Change from draft to not draft EXCEPT cancelled: The issue has been opened -> set the opening date
|
||||
if issue.state == 'draft' and state not in ('draft', 'cancelled'):
|
||||
vals['date_open'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
# Change from not done to done: The issue has been closed -> set the closing date
|
||||
if issue.state != 'done' and state == 'done':
|
||||
vals['date_closed'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
vals['date_last_stage_update'] = fields.datetime.now()
|
||||
# user_id change: update date_start
|
||||
if vals.get('user_id'):
|
||||
vals['date_start'] = fields.datetime.now()
|
||||
|
||||
return super(project_issue, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
|
@ -423,13 +405,6 @@ class project_issue(base_stage, osv.osv):
|
|||
task = self.pool.get('project.task').browse(cr, uid, task_id, context=context)
|
||||
return {'value': {'user_id': task.user_id.id, }}
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
"""Resets case as draft
|
||||
"""
|
||||
res = super(project_issue, self).case_reset(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'date_open': False, 'date_closed': False})
|
||||
return res
|
||||
|
||||
def get_empty_list_help(self, cr, uid, help, context=None):
|
||||
context['empty_list_help_model'] = 'project.project'
|
||||
context['empty_list_help_id'] = context.get('default_project_id')
|
||||
|
@ -478,11 +453,6 @@ class project_issue(base_stage, osv.osv):
|
|||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
""" Cancels case """
|
||||
self.case_set(cr, uid, ids, 'cancelled', {'active': True}, context=context)
|
||||
return True
|
||||
|
||||
def case_escalate(self, cr, uid, ids, context=None):
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
|
@ -591,7 +561,7 @@ class project_issue(base_stage, osv.osv):
|
|||
context = {}
|
||||
res = super(project_issue, self).message_post(cr, uid, thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, attachments=attachments, context=context, content_subtype=content_subtype, **kwargs)
|
||||
if thread_id and subtype:
|
||||
self.write(cr, SUPERUSER_ID, thread_id, {'date_action_last': time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
|
||||
self.write(cr, SUPERUSER_ID, thread_id, {'date_action_last': fields.datetime.now()}, context=context)
|
||||
return res
|
||||
|
||||
|
||||
|
@ -605,7 +575,7 @@ class project(osv.Model):
|
|||
res = dict.fromkeys(ids, 0)
|
||||
issue_ids = self.pool.get('project.issue').search(cr, uid, [('project_id', 'in', ids)])
|
||||
for issue in self.pool.get('project.issue').browse(cr, uid, issue_ids, context):
|
||||
if issue.state not in ('done', 'cancelled'):
|
||||
if issue.stage_id and not issue.stage_id.fold:
|
||||
res[issue.project_id.id] += 1
|
||||
return res
|
||||
|
||||
|
|
|
@ -35,11 +35,11 @@ Access all issues from the top Project menu, and access the issues of a specific
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Issue created</field>
|
||||
</record>
|
||||
<record id="mt_issue_started" model="mail.message.subtype">
|
||||
<field name="name">Issue Started</field>
|
||||
<record id="mt_issue_assigned" model="mail.message.subtype">
|
||||
<field name="name">Issue Assigned</field>
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Issue started</field>
|
||||
<field name="description">Issue assigned</field>
|
||||
</record>
|
||||
<record id="mt_issue_blocked" model="mail.message.subtype">
|
||||
<field name="name">Issue Blocked</field>
|
||||
|
@ -47,12 +47,6 @@ Access all issues from the top Project menu, and access the issues of a specific
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Issue blocked</field>
|
||||
</record>
|
||||
<record id="mt_issue_closed" model="mail.message.subtype">
|
||||
<field name="name">Issue Closed</field>
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Issue closed</field>
|
||||
</record>
|
||||
<record id="mt_issue_stage" model="mail.message.subtype">
|
||||
<field name="name">Stage Changed</field>
|
||||
<field name="res_model">project.issue</field>
|
||||
|
@ -67,11 +61,11 @@ Access all issues from the top Project menu, and access the issues of a specific
|
|||
<field name="parent_id" eval="ref('mt_issue_new')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_issue_started" model="mail.message.subtype">
|
||||
<field name="name">Issue Started</field>
|
||||
<record id="mt_project_issue_assigned" model="mail.message.subtype">
|
||||
<field name="name">Issue Assigned</field>
|
||||
<field name="res_model">project.project</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="parent_id" eval="ref('mt_issue_started')"/>
|
||||
<field name="parent_id" eval="ref('mt_issue_assigned')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_issue_blocked" model="mail.message.subtype">
|
||||
|
@ -80,12 +74,6 @@ Access all issues from the top Project menu, and access the issues of a specific
|
|||
<field name="parent_id" eval="ref('mt_issue_blocked')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_issue_closed" model="mail.message.subtype">
|
||||
<field name="name">Issue Closed</field>
|
||||
<field name="res_model">project.project</field>
|
||||
<field name="parent_id" eval="ref('mt_issue_closed')"/>
|
||||
<field name="relation_field">project_id</field>
|
||||
</record>
|
||||
<record id="mt_project_issue_stage" model="mail.message.subtype">
|
||||
<field name="name">Issue Stage Changed</field>
|
||||
<field name="res_model">project.project</field>
|
||||
|
|
|
@ -48,12 +48,6 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Issue" version="7.0">
|
||||
<header>
|
||||
<button name="case_close" string="Done" type="object"
|
||||
states="open" groups="base.group_user"/>
|
||||
<button name="case_close" string="Done" type="object"
|
||||
states="draft,pending" groups="base.group_user"/>
|
||||
<button name="case_cancel" string="Cancel Issue" type="object"
|
||||
states="draft,open,pending" groups="base.group_user"/>
|
||||
<field name="stage_id" widget="statusbar" clickable="True"/>
|
||||
</header>
|
||||
<sheet string="Issue">
|
||||
|
@ -76,7 +70,7 @@
|
|||
<label for="project_id"/>
|
||||
<div>
|
||||
<field name="project_id" on_change="on_change_project(project_id)" class="oe_inline" context="{'default_use_issues':1}"/>
|
||||
<button name="case_escalate" string="⇒ Escalate" type="object" states="draft,open,pending" class="oe_link"
|
||||
<button name="case_escalate" string="⇒ Escalate" type="object" class="oe_link"
|
||||
groups="base.group_user"/>
|
||||
</div>
|
||||
</group>
|
||||
|
@ -106,7 +100,6 @@
|
|||
</group>
|
||||
<group string="Status" groups="base.group_no_one">
|
||||
<field name="active"/>
|
||||
<field name="state" string="Status"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
|
@ -123,7 +116,7 @@
|
|||
<field name="name">Project Issue Tracker Tree</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Issue Tracker Tree" fonts="bold:message_unread==True" colors="black:state=='open';blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<tree string="Issue Tracker Tree" fonts="bold:message_unread==True">
|
||||
<field name="message_unread" invisible="1"/>
|
||||
<field name="id"/>
|
||||
<field name="name"/>
|
||||
|
@ -135,7 +128,6 @@
|
|||
<field name="user_id"/>
|
||||
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="categ_ids" invisible="1"/>
|
||||
<field name="task_id" invisible="1"/>
|
||||
</tree>
|
||||
|
@ -149,17 +141,16 @@
|
|||
<search string="Issue Tracker Search">
|
||||
<field name="name" string="Issue" filter_domain="['|', '|', '|', ('partner_id','child_of',self), ('description','ilike',self),('email_from','ilike',self),('name','ilike',self)]"/>
|
||||
<field name="id"/>
|
||||
<filter icon="terp-mail-message-new" string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id', '=', False)]"/>
|
||||
<filter string="New" name="draft" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<separator/>
|
||||
<filter name="filter_new" string="New" icon="terp-document-new" domain="[('state','=','draft')]" help="New Issues"/>
|
||||
<filter name="filter_open" string="To Do" domain="[('state','=','open')]" help="To Do Issues" icon="terp-check"/>
|
||||
<separator/>
|
||||
<filter string="Unassigned Issues" domain="[('user_id','=',False)]" help="Unassigned Issues" icon="terp-personal-"/>
|
||||
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<field name="user_id"/>
|
||||
<field name="project_id"/>
|
||||
<field name="categ_ids"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<group expand="0" string="Group By..." >
|
||||
<filter string="Responsible" name="group_user_id" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Contact" name="group_partner_id" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
|
@ -269,7 +260,7 @@
|
|||
<field name="name">Project Issue- Feature Tracker Tree</field>
|
||||
<field name="model">project.issue</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Feature Tracker Tree" fonts="bold:message_unread==True" colors="red:state=='open';black:state in ('draft', 'cancel','done','pending')">
|
||||
<tree string="Feature Tracker Tree" fonts="bold:message_unread==True">
|
||||
<field name="id"/>
|
||||
<field name="message_unread" invisible="1"/>
|
||||
<field name="name" string="Feature description"/>
|
||||
|
@ -278,7 +269,6 @@
|
|||
<field name="version_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -20,17 +20,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import tools
|
||||
from openerp.addons.crm import crm
|
||||
|
||||
AVAILABLE_STATES = [
|
||||
('draft','Draft'),
|
||||
('open','Open'),
|
||||
('cancel', 'Cancelled'),
|
||||
('done', 'Closed'),
|
||||
('pending','Pending')
|
||||
]
|
||||
class project_issue_report(osv.osv):
|
||||
_name = "project.issue.report"
|
||||
_auto = False
|
||||
|
@ -38,18 +31,13 @@ class project_issue_report(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Year', size=64, required=False, readonly=True),
|
||||
'section_id':fields.many2one('crm.case.section', 'Sale Team', readonly=True),
|
||||
'state': fields.selection(AVAILABLE_STATES, 'Status', size=16, readonly=True),
|
||||
'month':fields.selection([('01', 'January'), ('02', 'February'), \
|
||||
('03', 'March'), ('04', 'April'),\
|
||||
('05', 'May'), ('06', 'June'), \
|
||||
('07', 'July'), ('08', 'August'),\
|
||||
('09', 'September'), ('10', 'October'),\
|
||||
('11', 'November'), ('12', 'December')], 'Month', readonly=True),
|
||||
'month':fields.selection(fields.date.MONTHS, 'Month', readonly=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'opening_date': fields.date('Date of Opening', readonly=True),
|
||||
'creation_date': fields.date('Creation Date', readonly=True),
|
||||
'date_closed': fields.date('Date of Closing', readonly=True),
|
||||
'date_last_stage_update': fields.date('Last Stage Update', readonly=True),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'nbr': fields.integer('# of Issues', readonly=True),
|
||||
'working_hours_open': fields.float('Avg. Working Hours to Open', readonly=True, group_operator="avg"),
|
||||
|
@ -80,7 +68,7 @@ class project_issue_report(osv.osv):
|
|||
to_char(c.create_date, 'YYYY-MM-DD') as day,
|
||||
to_char(c.date_open, 'YYYY-MM-DD') as opening_date,
|
||||
to_char(c.create_date, 'YYYY-MM-DD') as creation_date,
|
||||
c.state,
|
||||
date_trunc('day',c.date_last_stage_update) as date_last_stage_update,
|
||||
c.user_id,
|
||||
c.working_hours_open,
|
||||
c.working_hours_close,
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<field name="partner_id" invisible="1"/>
|
||||
<field name="task_id" invisible="1"/>
|
||||
<field name="date_closed" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="date_last_stage_update" invisible="1"/>
|
||||
<field name="day" invisible="1"/>
|
||||
<field name="nbr" string="#Project Issues" sum="#Number of Project Issues"/>
|
||||
<field name="delay_open" avg="Avg Opening Delay"/>
|
||||
|
@ -36,9 +36,9 @@
|
|||
<field name="model">project.issue.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph orientation="horizontal" string="Project Issue" type="bar">
|
||||
<field name="state"/>
|
||||
<field name="nbr" operator="+"/>
|
||||
<field group="True" name="user_id"/>
|
||||
<field name="user_id" group="True"/>
|
||||
<field name="stage_id" group="True"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -49,14 +49,15 @@
|
|||
<field name="arch" type="xml">
|
||||
<search string="Search">
|
||||
<field name="creation_date"/>
|
||||
<filter icon="terp-camera_test" string="New" domain="[('state','=','draft')]"/>
|
||||
<filter icon="terp-check" string="To Do" domain="[('state','=','open')]"/>
|
||||
<filter icon="terp-gtk-media-pause" string="Pending" domain="[('state','=','pending')]"/>
|
||||
<filter icon="terp-dialog-close" string="Done" domain="[('state','=','done')]"/>
|
||||
<field name="project_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="version_id"/>
|
||||
<field name="stage_id"/>
|
||||
<filter string="Unassigned" name="unassigned" domain="[('user_id','=',False)]"/>
|
||||
<filter string="New" name="new" domain="[('stage_id.sequence', '=', 1)]"/>
|
||||
<filter string="Done" name="done" domain="[('stage_id.fold', '=', True)]"
|
||||
help="Tasks beloging to a folded stage"/>
|
||||
<group expand="1" string="Group By...">
|
||||
<filter string="Assigned to" name="Responsible" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}" />
|
||||
<filter string="Contact" icon="terp-partner" context="{'group_by':'partner_id'}" />
|
||||
|
@ -70,6 +71,7 @@
|
|||
<filter string="Day" icon="terp-go-today" domain="[]" context="{'group_by':'day'}" help="Creation Date"/>
|
||||
<filter string="Month" icon="terp-go-month" domain="[]" context="{'group_by':'month'}" help="Creation Date"/>
|
||||
<filter string="Year" icon="terp-go-year" domain="[]" context="{'group_by':'name'}" help="Creation Date"/>
|
||||
<filter string="Last Stage Update" context="{'group_by':'date_last_stage_update'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
-
|
||||
In order to test process of issue tracking in OpenERP, I cancel the unqualified Issue.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_cancel(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancelled'
|
||||
-
|
||||
I re-open the Issue.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_open(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check the state of issue after open it.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in open state}:
|
||||
- state == 'open'
|
||||
-
|
||||
I put the issue in pending state.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_pending(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check the state of issue after put it in pending state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue should be in pending state}:
|
||||
- state == 'pending'
|
||||
-
|
||||
I cancel the issue is in pending state.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_cancel(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancelled'
|
||||
-
|
||||
I close Issue.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_close(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check state of Issue after close.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in done state}:
|
||||
- state == 'done'
|
||||
-
|
||||
I cancel the issue is in done state.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_cancel(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancelled'
|
|
@ -1,23 +1,3 @@
|
|||
-
|
||||
In order to test process of issue tracking in OpenERP, I Open the Issue.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_open(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check state of Issue after opened it.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue should be in open state}:
|
||||
- state == 'open'
|
||||
-
|
||||
Now I put Issue in pending due to need more information.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_pending(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check state after put in pending.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue should be in pending state}:
|
||||
- state == 'pending'
|
||||
-
|
||||
I send mail to get more details. TODO revert mail.mail to mail.compose.message (conversion to customer should be automatic).
|
||||
-
|
||||
|
@ -29,29 +9,9 @@
|
|||
new_id = self.create(cr, uid, {'email_from': 'support@mycompany.com','email_to': 'Robert_Adersen@yahoo.com', 'subject': 'Regarding error in account module we nees more details'})
|
||||
self.send_mail(cr, uid, [new_id], context=ctx)
|
||||
except Exception, e:
|
||||
pass
|
||||
-
|
||||
After getting sufficient details, I re-open Issue from pending state.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_open(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I check state of Issue after re-opened.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue should be in open state}:
|
||||
- state == 'open'
|
||||
pass
|
||||
-
|
||||
I create Task for Issue.
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.convert_issue_task(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I close Issue after resolving it
|
||||
-
|
||||
!python {model: project.issue}: |
|
||||
self.case_close(cr, uid, [ref("crm_case_buginaccountsmodule0")])
|
||||
-
|
||||
I Check state of Issue after closed.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue should be in done state}:
|
||||
- state == 'done'
|
||||
|
|
|
@ -8,13 +8,13 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:06+0000\n"
|
||||
"PO-Revision-Date: 2013-07-07 04:44+0000\n"
|
||||
"PO-Revision-Date: 2013-07-14 03:57+0000\n"
|
||||
"Last-Translator: Alan <shuchuan.wu@gmail.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-08 05:25+0000\n"
|
||||
"X-Launchpad-Export-Date: 2013-07-15 04:51+0000\n"
|
||||
"X-Generator: Launchpad (build 16696)\n"
|
||||
|
||||
#. module: project_long_term
|
||||
|
@ -41,7 +41,7 @@ msgstr "阶段"
|
|||
#: view:project.phase:0
|
||||
#: view:project.user.allocation:0
|
||||
msgid "Team Planning"
|
||||
msgstr ""
|
||||
msgstr "项目团队计划"
|
||||
|
||||
#. module: project_long_term
|
||||
#: field:project.phase,user_ids:0
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
<field name="project_id" invisible="1"/>
|
||||
<field name="total_hours" sum='Total Hours'/>
|
||||
<field name="remaining_hours" widget="float_time" sum="Remaining Hours"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
|
|
@ -4,9 +4,6 @@ access_project_user_allocation,project.user.allocation,model_project_user_alloca
|
|||
access_project_phase_manager,project.phase manager,model_project_phase,project.group_project_manager,1,1,1,1
|
||||
access_project_user_allocation_manager,project.user.allocation manager,model_project_user_allocation,project.group_project_manager,1,1,1,1
|
||||
access_resource_resource_user,user.user user,resource.model_resource_resource,project.group_project_user,1,0,0,0
|
||||
access_resource_calendar_leaves_user,user.calendar.leaves user,resource.model_resource_calendar_leaves,project.group_project_user,1,1,1,1
|
||||
access_resource_resource_manager,user.user manager,resource.model_resource_resource,project.group_project_manager,1,1,1,1
|
||||
access_project_user_allocation_manager,project.user.allocation.manager,model_project_user_allocation,project.group_project_manager,1,1,1,1
|
||||
access_project_resource_calendar_attendance,resource.calendar.attendance,resource.model_resource_calendar_attendance,project.group_project_manager,1,0,0,0
|
||||
|
||||
|
||||
|
|
|
|
@ -14,6 +14,6 @@
|
|||
!python {model: project.project}: |
|
||||
prj = self.browse(cr, uid, [ref("project.project_project_1")])[0]
|
||||
for task in prj.tasks:
|
||||
if task.state in ('done','cancelled'):
|
||||
if task.stage_id and task.stage_id.fold:
|
||||
continue
|
||||
assert task.user_id and task.date_start and task.date_end, "Project tasks not scheduled"
|
||||
|
|
|
@ -22,6 +22,23 @@
|
|||
from openerp.osv import fields, osv
|
||||
from openerp import netsvc
|
||||
|
||||
|
||||
class ProjectTaskStageMrp(osv.Model):
|
||||
""" Override project.task.type model to add a 'closed' boolean field allowing
|
||||
to know that tasks in this stage are considered as closed. Indeed since
|
||||
OpenERP 8.0 status is not present on tasks anymore, only stage_id. """
|
||||
_name = 'project.task.type'
|
||||
_inherit = 'project.task.type'
|
||||
|
||||
_columns = {
|
||||
'closed': fields.boolean('Close', help="Tasks in this stage are considered as closed."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'closed': False,
|
||||
}
|
||||
|
||||
|
||||
class project_task(osv.osv):
|
||||
_name = "project.task"
|
||||
_inherit = "project.task"
|
||||
|
@ -30,21 +47,21 @@ class project_task(osv.osv):
|
|||
'sale_line_id': fields.related('procurement_id', 'sale_line_id', type='many2one', relation='sale.order.line', store=True, string='Sales Order Line'),
|
||||
}
|
||||
|
||||
def _validate_subflows(self, cr, uid, ids):
|
||||
def _validate_subflows(self, cr, uid, ids, context=None):
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
for task in self.browse(cr, uid, ids):
|
||||
if task.procurement_id:
|
||||
wf_service.trg_write(uid, 'procurement.order', task.procurement_id.id, cr)
|
||||
|
||||
def do_close(self, cr, uid, ids, *args, **kwargs):
|
||||
res = super(project_task, self).do_close(cr, uid, ids, *args, **kwargs)
|
||||
self._validate_subflows(cr, uid, ids)
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
""" When closing tasks, validate subflows. """
|
||||
res = super(project_task, self).write(cr, uid, ids, values, context=context)
|
||||
if values.get('stage_id'):
|
||||
stage = self.pool.get('project.task.type').browse(cr, uid, values.get('stage_id'), context=context)
|
||||
if stage.closed:
|
||||
self._validate_subflows(cr, uid, ids, context=context)
|
||||
return res
|
||||
|
||||
def do_cancel(self, cr, uid, ids, *args, **kwargs):
|
||||
res = super(project_task, self).do_cancel(cr, uid, ids, *args, **kwargs)
|
||||
self._validate_subflows(cr, uid, ids)
|
||||
return res
|
||||
|
||||
class product_product(osv.osv):
|
||||
_inherit = "product.product"
|
||||
|
@ -52,8 +69,9 @@ class product_product(osv.osv):
|
|||
'project_id': fields.many2one('project.project', 'Project', ondelete='set null',)
|
||||
}
|
||||
|
||||
|
||||
class sale_order(osv.osv):
|
||||
_inherit ='sale.order'
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None):
|
||||
proc_data = super(sale_order, self)._prepare_order_line_procurement(cr,
|
||||
|
@ -66,11 +84,12 @@ class sale_order(osv.osv):
|
|||
return {}
|
||||
res_sale = {}
|
||||
res = super(sale_order, self)._picked_rate(cr, uid, ids, name, arg, context=context)
|
||||
cr.execute('''select sol.order_id as sale_id, t.state as task_state ,
|
||||
cr.execute('''select sol.order_id as sale_id, stage.closed as task_closed ,
|
||||
t.id as task_id, sum(sol.product_uom_qty) as total
|
||||
from project_task as t
|
||||
left join sale_order_line as sol on sol.id = t.sale_line_id
|
||||
where sol.order_id in %s group by sol.order_id,t.state,t.id ''',(tuple(ids),))
|
||||
left join project_task_type as stage on stage.id = t.stage_id
|
||||
where sol.order_id in %s group by sol.order_id,stage.closed,t.id ''',(tuple(ids),))
|
||||
sale_task_data = cr.dictfetchall()
|
||||
|
||||
if not sale_task_data:
|
||||
|
@ -90,7 +109,7 @@ class sale_order(osv.osv):
|
|||
|
||||
for item in sale_task_data:
|
||||
res_sale[item['sale_id']]['total_no_task'] += item['total']
|
||||
if item['task_state'] == 'done':
|
||||
if item['task_closed']:
|
||||
res_sale[item['sale_id']]['number_of_done'] += item['total']
|
||||
|
||||
for sale in self.browse(cr, uid, ids, context=context):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!--Resource: sale.order.line for services type product-->
|
||||
|
||||
<record id="line_services" model="sale.order.line">
|
||||
|
@ -14,5 +13,8 @@
|
|||
<field name="type">make_to_order</field>
|
||||
</record>
|
||||
|
||||
<record id="project.project_tt_deployment" model="project.task.type">
|
||||
<field name="closed" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -21,14 +21,24 @@
|
|||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="task_type_edit_mrp_inherit" model="ir.ui.view">
|
||||
<field name="name">project.task.type.mrp.inherit</field>
|
||||
<field name="model">project.task.type</field>
|
||||
<field name="inherit_id" ref="project.task_type_edit"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="case_default" position="after">
|
||||
<field name="closed"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_project_mrp_inherit_form2" model="ir.ui.view">
|
||||
<field name="name">project.mrp.form.view.inherit</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@string='Extra Info']//field[@name='state']" position="after">
|
||||
<field name="company_id" position="before">
|
||||
<field name="sale_line_id" string="Order Line"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="product_product_normal_form_supply_view" model="ir.ui.view">
|
||||
|
|
|
@ -33,13 +33,13 @@ class procurement_order(osv.osv):
|
|||
def action_check_finished(self, cr, uid, ids):
|
||||
res = super(procurement_order, self).action_check_finished(cr, uid, ids)
|
||||
return res and self.check_task_done(cr, uid, ids)
|
||||
|
||||
|
||||
def check_task_done(self, cr, uid, ids, context=None):
|
||||
""" Checks if task is done or not.
|
||||
@return: True or False.
|
||||
"""
|
||||
for p in self.browse(cr, uid, ids, context=context):
|
||||
if (p.product_id.type=='service') and (p.procure_method=='make_to_order') and p.task_id and (p.task_id.state not in ('done', 'cancelled')):
|
||||
if (p.product_id.type == 'service') and (p.procure_method == 'make_to_order') and p.task_id and (p.task_id.stage_id and not p.task_id.stage_id.closed):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
!python {model: project.task}: |
|
||||
task_ids = self.search(cr, uid, [('sale_line_id', '=', ref('line_services'))])
|
||||
assert task_ids, "Task is not generated for Service Order Line."
|
||||
self.do_close(cr, uid, task_ids, context=context)
|
||||
self.write(cr, uid, task_ids, {'stage_id': ref('project.project_tt_deployment')}, context=context)
|
||||
-
|
||||
I check procurement of Service Order Line after closed task.
|
||||
-
|
||||
|
@ -44,4 +44,4 @@
|
|||
procurement_ids = self.search(cr, uid, [('sale_line_id', '=', ref('line_services'))])
|
||||
assert procurement_ids, "Procurement is not generated for Service Order Line."
|
||||
procurement = self.browse(cr, uid, procurement_ids[0], context=context)
|
||||
assert procurement.state == 'done' , "Procurement should be closed."
|
||||
assert procurement.state == 'done' , "Procurement should be closed."
|
|
@ -66,16 +66,7 @@
|
|||
planned_hours: 20.0
|
||||
project_id: project_project_timesheetmanagement0
|
||||
remaining_hours: 20.0
|
||||
state: draft
|
||||
user_id: res_users_hrmanager0
|
||||
-
|
||||
Open the task
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.do_open(cr, uid, [ref("project_task_getalltimesheetrecords0")], {"lang":
|
||||
"en_US", "active_ids": [ref("project_project_timesheetmanagement0")], "tz":
|
||||
False, "active_model": "project.project", "department_id": False, "project_id":
|
||||
False, "active_id": ref("project_project_timesheetmanagement0"), })
|
||||
-
|
||||
Make a work task entry 'Get work calendar of all employees' of 10 hours done by HR manager
|
||||
-
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
Automate procurement propositions, launch request for quotations, track purchase orders, manage suppliers' information, control products reception and check suppliers' invoices.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=purchase" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@ you need, easily accessible. Keep track of long term contracts, automate invoici
|
|||
and notify sales when they have things to do.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=sale" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
Decrease your process times, automate transactions, reduce your stock levels and get complete traceability on all operations with the OpenERP double entry inventory system.
|
||||
</p>
|
||||
<div class="oe_centeralign oe_websiteonly">
|
||||
<a href="http://www.openerp.com/start" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
<a href="http://www.openerp.com/start?app=stock" class="oe_button oe_big oe_tacky">Start your <span class="oe_emph">free</span> trial</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue