[IMP] Contract management + fixes
bzr revid: fp@tinyerp.com-20111116145958-pzp36c49wh6028p9
This commit is contained in:
parent
1d54432f87
commit
36acb24ce4
|
@ -91,15 +91,18 @@
|
||||||
</group>
|
</group>
|
||||||
<notebook colspan="4">
|
<notebook colspan="4">
|
||||||
<page string="Account Data">
|
<page string="Account Data">
|
||||||
<field name="partner_id"/>
|
<group colspan="2" col="2">
|
||||||
<field name="contact_id"/>
|
<separator colspan="2" string="Contacts"/>
|
||||||
<field name="currency_id"/>
|
<field name="partner_id" on_change="on_change_partner_id(partner_id)"/>
|
||||||
<newline/>
|
<field name="contact_id"/>
|
||||||
<field name="date_start"/>
|
<field name="user_id"/>
|
||||||
<field name="date"/>
|
</group>
|
||||||
<newline/>
|
<group colspan="2" col="2" name="contract">
|
||||||
<field name="quantity_max"/>
|
<separator colspan="2" string="Contract Data"/>
|
||||||
<field name="user_id"/>
|
<field name="date_start"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="quantity_max"/>
|
||||||
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Description">
|
<page string="Description">
|
||||||
<field colspan="4" name="description" nolabel="1"/>
|
<field colspan="4" name="description" nolabel="1"/>
|
||||||
|
|
|
@ -376,13 +376,11 @@ class account_analytic_account(osv.osv):
|
||||||
|
|
||||||
def _is_overdue_quantity(self, cr, uid, ids, fieldnames, args, context=None):
|
def _is_overdue_quantity(self, cr, uid, ids, fieldnames, args, context=None):
|
||||||
result = dict.fromkeys(ids, 0)
|
result = dict.fromkeys(ids, 0)
|
||||||
|
|
||||||
for record in self.browse(cr, uid, ids, context=context):
|
for record in self.browse(cr, uid, ids, context=context):
|
||||||
if record.quantity == 0.0 and record.quantity_max == 0.0:
|
if record.quantity_max > 0.0:
|
||||||
result[record.id] = 0
|
|
||||||
else:
|
|
||||||
result[record.id] = int(record.quantity >= record.quantity_max)
|
result[record.id] = int(record.quantity >= record.quantity_max)
|
||||||
|
else:
|
||||||
|
result[record.id] = 0
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _get_analytic_account(self, cr, uid, ids, context=None):
|
def _get_analytic_account(self, cr, uid, ids, context=None):
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<openerp>
|
<openerp>
|
||||||
<data>
|
<data>
|
||||||
<menuitem icon="terp-project" id="base.menu_main_pm" name="Project" sequence="10"/>
|
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5"/>
|
||||||
<menuitem id="menu_invoicing" name="Billing" parent="base.menu_main_pm" sequence="4" groups="base.group_extended"/>
|
|
||||||
|
|
||||||
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">
|
<record id="action_hr_tree_invoiced_all" model="ir.actions.act_window">
|
||||||
<field name="name">All Uninvoiced Entries</field>
|
<field name="name">All Uninvoiced Entries</field>
|
||||||
|
@ -11,16 +10,7 @@
|
||||||
<field name="domain">[('invoice_id','=',False)]</field>
|
<field name="domain">[('invoice_id','=',False)]</field>
|
||||||
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
|
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
|
||||||
</record>
|
</record>
|
||||||
<menuitem action="action_hr_tree_invoiced_all" id="menu_action_hr_tree_invoiced_all" parent="menu_invoicing" groups="analytic.group_analytic_accounting"/>
|
<menuitem action="action_hr_tree_invoiced_all" id="menu_action_hr_tree_invoiced_all" parent="base.menu_invoiced"/>
|
||||||
|
|
||||||
<record id="action_account_analytic_managed_overpassed" model="ir.actions.act_window">
|
|
||||||
<field name="name">Overpassed Accounts</field>
|
|
||||||
<field name="res_model">account.analytic.account</field>
|
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form,graph</field>
|
|
||||||
<field name="domain">[('date','<=',time.strftime('%Y-%m-%d')),('state','=','open')]</field>
|
|
||||||
</record>
|
|
||||||
<menuitem action="action_account_analytic_managed_overpassed" id="menu_action_account_analytic_managed_overpassed" sequence="50" parent="menu_invoicing" groups="base.group_extended"/>
|
|
||||||
|
|
||||||
<record id="view_account_analytic_account_overdue_search" model="ir.ui.view">
|
<record id="view_account_analytic_account_overdue_search" model="ir.ui.view">
|
||||||
<field name="name">account.analytic.account.search</field>
|
<field name="name">account.analytic.account.search</field>
|
||||||
|
@ -29,11 +19,10 @@
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<search string="Analytic Account">
|
<search string="Analytic Account">
|
||||||
<group col="8" colspan="4">
|
<group col="8" colspan="4">
|
||||||
<filter icon="terp-check" name="draft" string="Draft" domain="[('state','=','draft')]" help="Contracts not signed yet"/>
|
<filter icon="terp-camera_test" name="open" string="Open" domain="[('state','in',('open','draft'))]" help="Contracts in progress"/>
|
||||||
<filter icon="terp-camera_test" name="open" string="Open" domain="[('state','=','open')]" help="Contracts in progress"/>
|
|
||||||
<filter icon="terp-gtk-media-pause" name="pending" string="Pending" domain="[('state','=','pending')]" help="Pending contracts to renew with your customer"/>
|
<filter icon="terp-gtk-media-pause" name="pending" string="Pending" domain="[('state','=','pending')]" help="Pending contracts to renew with your customer"/>
|
||||||
<separator orientation="vertical"/>
|
<separator orientation="vertical"/>
|
||||||
<filter icon="terp-go-today" string="To Renew" domain="['|', '&', ('date', '!=', False), ('date', '<', time.strftime('%%Y-%%m-%%d')), ('is_overdue_quantity', '=', True)]"
|
<filter icon="terp-go-today" string="To Renew" domain="['|', '&', ('date', '!=', False), ('date', '<=', time.strftime('%%Y-%%m-%%d')), ('is_overdue_quantity', '=', True)]"
|
||||||
name="renew"
|
name="renew"
|
||||||
help="The contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours" />
|
help="The contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours" />
|
||||||
<filter icon="terp-go-month"
|
<filter icon="terp-go-month"
|
||||||
|
@ -71,7 +60,7 @@
|
||||||
|
|
||||||
|
|
||||||
<record id="action_account_analytic_overdue" model="ir.actions.act_window">
|
<record id="action_account_analytic_overdue" model="ir.actions.act_window">
|
||||||
<field name="name">Overdue Accounts</field>
|
<field name="name">Analytic Accounts/Contracts</field>
|
||||||
<field name="res_model">account.analytic.account</field>
|
<field name="res_model">account.analytic.account</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form,graph</field>
|
<field name="view_mode">tree,form,graph</field>
|
||||||
|
@ -80,7 +69,7 @@
|
||||||
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
|
<field name="search_view_id" ref="view_account_analytic_account_overdue_search"/>
|
||||||
<field name="help">You will find here the contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours. OpenERP automatically sets these analytic accounts to the pending state, in order to raise a warning during the timesheets recording. Salesmen should review all pending accounts and reopen or close the according to the negotiation with the customer.</field>
|
<field name="help">You will find here the contracts to be renewed because the deadline is passed or the working hours are higher than the allocated hours. OpenERP automatically sets these analytic accounts to the pending state, in order to raise a warning during the timesheets recording. Salesmen should review all pending accounts and reopen or close the according to the negotiation with the customer.</field>
|
||||||
</record>
|
</record>
|
||||||
<menuitem action="action_account_analytic_overdue" id="menu_action_account_analytic_overdue" sequence="50" parent="sale.menu_invoiced" groups="base.group_extended"/>
|
<menuitem action="action_account_analytic_overdue" id="menu_action_account_analytic_overdue" sequence="50" parent="base.menu_invoiced"/>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -8,6 +8,27 @@
|
||||||
Remove information on Account data => because they move on analysis sheet
|
Remove information on Account data => because they move on analysis sheet
|
||||||
create a page with invoicing informations
|
create a page with invoicing informations
|
||||||
-->
|
-->
|
||||||
|
<record id="account_analytic_account_invoice_stat_form" model="ir.ui.view">
|
||||||
|
<field name="name">account.analytic.account.invoice.stat.form.inherit</field>
|
||||||
|
<field name="model">account.analytic.account</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="inherit_id" ref="hr_timesheet_invoice.account_analytic_account_form_form"/>
|
||||||
|
<field eval="18" name="priority"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<group name="invoice_stats" position="inside">
|
||||||
|
<field name="hours_qtt_non_invoiced"/>
|
||||||
|
<field name="ca_to_invoice"/>
|
||||||
|
<label string="" colspan="1"/>
|
||||||
|
<button
|
||||||
|
name="%(hr_timesheet_invoice.action_hr_timesheet_invoice_create_final)d"
|
||||||
|
string="Create Invoice"
|
||||||
|
type="action"
|
||||||
|
attrs="{'readonly':[('ca_to_invoice','=',0.0)]}"
|
||||||
|
icon="gtk-go-forward"/>
|
||||||
|
</group>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record id="hr_timesheet.account_analytic_account_form_form" model="ir.ui.view">
|
<record id="hr_timesheet.account_analytic_account_form_form" model="ir.ui.view">
|
||||||
<field name="name">account.analytic.account.invoice.form.inherit</field>
|
<field name="name">account.analytic.account.invoice.form.inherit</field>
|
||||||
<field name="model">account.analytic.account</field>
|
<field name="model">account.analytic.account</field>
|
||||||
|
@ -16,7 +37,7 @@
|
||||||
<field eval="18" name="priority"/>
|
<field eval="18" name="priority"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<notebook position="inside">
|
<notebook position="inside">
|
||||||
<page string="Analysis summary">
|
<page string="Invoice Analysis">
|
||||||
<separator colspan="4" string="Work done stats"/>
|
<separator colspan="4" string="Work done stats"/>
|
||||||
|
|
||||||
<field name="total_cost"/>
|
<field name="total_cost"/>
|
||||||
|
@ -39,10 +60,6 @@
|
||||||
<field name="last_invoice_date"/>
|
<field name="last_invoice_date"/>
|
||||||
<field name="last_worked_invoiced_date"/>
|
<field name="last_worked_invoiced_date"/>
|
||||||
<field name="last_worked_date"/>
|
<field name="last_worked_date"/>
|
||||||
<separator colspan="4" string="To be invoiced"/>
|
|
||||||
|
|
||||||
<field name="hours_qtt_non_invoiced"/>
|
|
||||||
<field name="ca_to_invoice"/>
|
|
||||||
</page>
|
</page>
|
||||||
<page string="Stats by month">
|
<page string="Stats by month">
|
||||||
<field colspan="4" name="month_ids" nolabel="1">
|
<field colspan="4" name="month_ids" nolabel="1">
|
||||||
|
|
|
@ -150,7 +150,7 @@ class account_analytic_account(osv.osv):
|
||||||
_columns = {
|
_columns = {
|
||||||
'name': fields.char('Account Name', size=128, required=True),
|
'name': fields.char('Account Name', size=128, required=True),
|
||||||
'complete_name': fields.function(_complete_name_calc, type='char', string='Full Account Name'),
|
'complete_name': fields.function(_complete_name_calc, type='char', string='Full Account Name'),
|
||||||
'code': fields.char('Account Code', size=24, select=True),
|
'code': fields.char('Code/Reference', size=24, select=True),
|
||||||
'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type', help='If you select the View Type, it means you won\'t allow to create journal entries using that account.'),
|
'type': fields.selection([('view','View'), ('normal','Normal')], 'Account Type', help='If you select the View Type, it means you won\'t allow to create journal entries using that account.'),
|
||||||
'description': fields.text('Description'),
|
'description': fields.text('Description'),
|
||||||
'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
|
'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
|
||||||
|
@ -168,7 +168,7 @@ class account_analytic_account(osv.osv):
|
||||||
'date_start': fields.date('Date Start'),
|
'date_start': fields.date('Date Start'),
|
||||||
'date': fields.date('Date End', select=True),
|
'date': fields.date('Date End', select=True),
|
||||||
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
|
'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
|
||||||
'state': fields.selection([('draft','New'),('open','Started'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Closed'),('template', 'Template')], 'State', required=True,
|
'state': fields.selection([('template', 'Template'),('draft','New'),('open','Open'), ('pending','Pending'),('cancelled', 'Cancelled'),('close','Closed')], 'State', required=True,
|
||||||
help='* When an account is created its in \'Draft\' state.\
|
help='* When an account is created its in \'Draft\' state.\
|
||||||
\n* If any associated partner is there, it can be in \'Open\' state.\
|
\n* If any associated partner is there, it can be in \'Open\' state.\
|
||||||
\n* If any pending balance is there it can be in \'Pending\'. \
|
\n* If any pending balance is there it can be in \'Pending\'. \
|
||||||
|
@ -217,6 +217,12 @@ class account_analytic_account(osv.osv):
|
||||||
default['line_ids'] = []
|
default['line_ids'] = []
|
||||||
return super(account_analytic_account, self).copy(cr, uid, id, default, context=context)
|
return super(account_analytic_account, self).copy(cr, uid, id, default, context=context)
|
||||||
|
|
||||||
|
def on_change_partner_id(self, cr, uid, id, partner_id, context={}):
|
||||||
|
if not partner_id:
|
||||||
|
return {'value': {'contact_id': False}}
|
||||||
|
addr = self.pool.get('res.partner').address_get(cr, uid, [partner_id], ['invoice'])
|
||||||
|
return {'value': {'contact_id': addr.get('invoice', False)}}
|
||||||
|
|
||||||
def on_change_company(self, cr, uid, id, company_id):
|
def on_change_company(self, cr, uid, id, company_id):
|
||||||
if not company_id:
|
if not company_id:
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -63,12 +63,12 @@ class account_analytic_account(osv.osv):
|
||||||
|
|
||||||
_inherit = "account.analytic.account"
|
_inherit = "account.analytic.account"
|
||||||
_columns = {
|
_columns = {
|
||||||
'pricelist_id': fields.many2one('product.pricelist', 'Sale Pricelist',
|
'pricelist_id': fields.many2one('product.pricelist', 'Customer Pricelist',
|
||||||
help="The product to invoice is defined on the employee form, the price will be deduced by this pricelist on the product."),
|
help="The product to invoice is defined on the employee form, the price will be deduced by this pricelist on the product."),
|
||||||
'amount_max': fields.float('Max. Invoice Price'),
|
'amount_max': fields.float('Max. Invoice Price'),
|
||||||
'amount_invoiced': fields.function(_invoiced_calc, string='Invoiced Amount',
|
'amount_invoiced': fields.function(_invoiced_calc, string='Invoiced Amount',
|
||||||
help="Total invoiced"),
|
help="Total invoiced"),
|
||||||
'to_invoice': fields.many2one('hr_timesheet_invoice.factor', 'Reinvoice Costs',
|
'to_invoice': fields.many2one('hr_timesheet_invoice.factor', 'Invoice on Timesheet & Costs',
|
||||||
help="Fill this field if you plan to automatically generate invoices based " \
|
help="Fill this field if you plan to automatically generate invoices based " \
|
||||||
"on the costs in this analytic account: timesheets, expenses, ..." \
|
"on the costs in this analytic account: timesheets, expenses, ..." \
|
||||||
"You can configure an automatic invoice rate on analytic accounts."),
|
"You can configure an automatic invoice rate on analytic accounts."),
|
||||||
|
@ -76,7 +76,16 @@ class account_analytic_account(osv.osv):
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'pricelist_id': lambda self, cr, uid, ctx: ctx.get('pricelist_id', False),
|
'pricelist_id': lambda self, cr, uid, ctx: ctx.get('pricelist_id', False),
|
||||||
}
|
}
|
||||||
|
def on_change_partner_id(self, cr, uid, id, partner_id, context={}):
|
||||||
|
res = super(account_analytic_account, self).on_change_partner_id(cr, uid, id, partner_id, context)
|
||||||
|
if (not res.get('value', False)) or not partner_id:
|
||||||
|
return res
|
||||||
|
part = self.pool.get('res.partner').browse(cr, uid, partner_id)
|
||||||
|
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
||||||
|
if pricelist:
|
||||||
|
res['value']['pricelist_id'] = pricelist
|
||||||
|
return res
|
||||||
|
|
||||||
def set_close(self, cr, uid, ids, context=None):
|
def set_close(self, cr, uid, ids, context=None):
|
||||||
return self.write(cr, uid, ids, {'state':'close'}, context=context)
|
return self.write(cr, uid, ids, {'state':'close'}, context=context)
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,27 @@
|
||||||
<field name="type">form</field>
|
<field name="type">form</field>
|
||||||
<field name="inherit_id" ref="account.view_account_analytic_account_form"/>
|
<field name="inherit_id" ref="account.view_account_analytic_account_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="user_id" position="after">
|
<group name="contract" position="after">
|
||||||
<group colspan="4" col="4">
|
<group colspan="2" col="2" name="invoice_data">
|
||||||
<separator colspan="4" string="Invoicing Data"/>
|
<separator colspan="2" string="Invoicing Data"/>
|
||||||
<field name="pricelist_id" domain="[('type','=','sale')]" widget="selection"/>
|
<field name="to_invoice" widget="selection"/>
|
||||||
<field name="to_invoice" widget="selection" />
|
<field name="pricelist_id" domain="[('type','=','sale')]" attrs="{'required':[('to_invoice','!=',False)]}"/>
|
||||||
<field name="amount_max"/>
|
<field name="amount_max"/>
|
||||||
<field name="amount_invoiced"/>
|
|
||||||
<separator colspan="4"/>
|
|
||||||
<group col="9" colspan="8">
|
|
||||||
<field name="state" readonly="1"/>
|
|
||||||
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
|
||||||
<button name="set_open" string="Reactivate Account" type="object" states="pending,cancelled,close,draft" icon="gtk-ok"/>
|
|
||||||
<button name="set_pending" string="Pending" type="object" states="open" icon="gtk-media-pause"/>
|
|
||||||
<button name="set_close" string="Close" type="object" states="open,pending" icon="terp-dialog-close"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
</group>
|
||||||
</field>
|
<group colspan="2" col="2" name="invoice_stats">
|
||||||
|
<separator colspan="4" string="Invoicing Statistics"/>
|
||||||
|
<field name="amount_invoiced"/>
|
||||||
|
</group>
|
||||||
|
<separator colspan="4"/>
|
||||||
|
<group col="9" colspan="8">
|
||||||
|
<field name="state" readonly="1" widget="statusbar"
|
||||||
|
statusbar_visible="open,pending,close" statusbar_colors='{"pending":"red", "template":"blue"}'/>
|
||||||
|
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
||||||
|
<button name="set_open" string="Reactivate Account" type="object" states="pending,cancelled,close,draft" icon="gtk-ok"/>
|
||||||
|
<button name="set_pending" string="Pending" type="object" states="open" icon="gtk-media-pause"/>
|
||||||
|
<button name="set_close" string="Close" type="object" states="open,pending" icon="terp-dialog-close"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
@ -123,7 +127,7 @@
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="domain">[]</field>
|
<field name="domain">[]</field>
|
||||||
<field name="context">{'search_default_to_invoice': 1}</field>
|
<field name="context">{'search_default_to_invoice': 1}</field>
|
||||||
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
|
<field name="search_view_id" ref="account.view_account_analytic_line_filter"/>
|
||||||
<field name="help">This list shows you every task you can invoice to the customer. Select the lines and click the Action button to generate the invoices automatically.</field>
|
<field name="help">This list shows you every task you can invoice to the customer. Select the lines and click the Action button to generate the invoices automatically.</field>
|
||||||
</record>
|
</record>
|
||||||
<menuitem
|
<menuitem
|
||||||
|
|
|
@ -39,145 +39,21 @@ class final_invoice_create(osv.osv_memory):
|
||||||
'time': fields.boolean('Time spent', help='Display time in the history of works'),
|
'time': fields.boolean('Time spent', help='Display time in the history of works'),
|
||||||
'name': fields.boolean('Name of entry', help='Display detail of work in the invoice line.'),
|
'name': fields.boolean('Name of entry', help='Display detail of work in the invoice line.'),
|
||||||
'price': fields.boolean('Cost', help='Display cost of the item you reinvoice'),
|
'price': fields.boolean('Cost', help='Display cost of the item you reinvoice'),
|
||||||
'balance_product': fields.many2one('product.product', 'Balance product', help='The product that will be used to invoice the remaining amount'),
|
'product': fields.many2one('product.product', 'Product', help='The product that will be used to invoice the remaining amount'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def do_create(self, cr, uid, ids, context=None):
|
def do_create(self, cr, uid, ids, context=None):
|
||||||
|
data = self.read(cr, uid, ids, [], context=context)[0]
|
||||||
|
ids = self.pool.get('account.analytic.line').search(cr, uid, [('invoice_id','=',False),('to_invoice','<>', False), ('account_id', 'in', context['active_ids'])], context=context)
|
||||||
|
invs = self.pool.get('account.analytic.line').invoice_cost_create(cr, uid, ids, data, context=context)
|
||||||
mod_obj = self.pool.get('ir.model.data')
|
mod_obj = self.pool.get('ir.model.data')
|
||||||
analytic_account_obj = self.pool.get('account.analytic.account')
|
act_obj = self.pool.get('ir.actions.act_window')
|
||||||
res_partner_obj = self.pool.get('res.partner')
|
mod_ids = mod_obj.search(cr, uid, [('name', '=', 'action_invoice_tree1')], context=context)[0]
|
||||||
account_payment_term_obj = self.pool.get('account.payment.term')
|
res_id = mod_obj.read(cr, uid, mod_ids, ['res_id'], context=context)['res_id']
|
||||||
invoice_obj = self.pool.get('account.invoice')
|
act_win = act_obj.read(cr, uid, res_id, [], context=context)
|
||||||
product_obj = self.pool.get('product.product')
|
act_win['domain'] = [('id','in',invs),('type','=','out_invoice')]
|
||||||
fiscal_pos_obj = self.pool.get('account.fiscal.position')
|
act_win['name'] = _('Invoices')
|
||||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
return act_win
|
||||||
invoices = []
|
|
||||||
|
|
||||||
if context is None:
|
|
||||||
context = {}
|
|
||||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_invoice_filter')
|
|
||||||
res = mod_obj.read(cr, uid, result, ['res_id'], context=context)
|
|
||||||
|
|
||||||
data = self.browse(cr, uid, ids, context=context)[0]
|
|
||||||
balance_product = data.balance_product.id
|
|
||||||
|
|
||||||
account_ids = 'active_ids' in context and context['active_ids'] or []
|
|
||||||
|
|
||||||
for account in analytic_account_obj.browse(cr, uid, account_ids, context=context):
|
|
||||||
partner = account.partner_id
|
|
||||||
amount_total=0.0
|
|
||||||
if (not partner) or not (account.pricelist_id):
|
|
||||||
raise osv.except_osv(_('Analytic account incomplete'),
|
|
||||||
_('Please fill in the partner and pricelist field '
|
|
||||||
'in the analytic account:\n%s') % (account.name,))
|
|
||||||
|
|
||||||
date_due = False
|
|
||||||
if partner.property_payment_term:
|
|
||||||
pterm_list= account_payment_term_obj.compute(cr, uid,
|
|
||||||
partner.property_payment_term.id, value=1,
|
|
||||||
date_ref=time.strftime('%Y-%m-%d'))
|
|
||||||
if pterm_list:
|
|
||||||
pterm_list = [line[0] for line in pterm_list]
|
|
||||||
pterm_list.sort()
|
|
||||||
date_due = pterm_list[-1]
|
|
||||||
|
|
||||||
curr_invoice = {
|
|
||||||
'name': time.strftime('%d/%m/%Y')+' - '+account.name,
|
|
||||||
'partner_id': account.partner_id.id,
|
|
||||||
'address_contact_id': res_partner_obj.address_get(cr, uid, [account.partner_id.id], adr_pref=['contact'])['contact'],
|
|
||||||
'address_invoice_id': res_partner_obj.address_get(cr, uid, [account.partner_id.id], adr_pref=['invoice'])['invoice'],
|
|
||||||
'payment_term': partner.property_payment_term.id or False,
|
|
||||||
'account_id': partner.property_account_receivable.id,
|
|
||||||
'currency_id': account.pricelist_id.currency_id.id,
|
|
||||||
'date_due': date_due,
|
|
||||||
'fiscal_position': account.partner_id.property_account_position.id
|
|
||||||
}
|
|
||||||
last_invoice = invoice_obj.create(cr, uid, curr_invoice, context=context)
|
|
||||||
invoices.append(last_invoice)
|
|
||||||
|
|
||||||
context2 = context.copy()
|
|
||||||
context2['lang'] = partner.lang
|
|
||||||
|
|
||||||
cr.execute("""SELECT
|
|
||||||
line.product_id,
|
|
||||||
sum(line.amount),
|
|
||||||
line.general_account_id,
|
|
||||||
line.product_uom_id,
|
|
||||||
move_line.ref
|
|
||||||
FROM
|
|
||||||
account_analytic_line as line
|
|
||||||
LEFT JOIN account_move_line as move_line on (line.move_id=move_line.id)
|
|
||||||
LEFT JOIN account_analytic_journal as journal on (line.journal_id=journal.id)
|
|
||||||
WHERE
|
|
||||||
line.account_id = %s AND
|
|
||||||
line.move_id IS NOT NULL AND
|
|
||||||
journal.type = 'sale'
|
|
||||||
GROUP BY
|
|
||||||
line.product_id,
|
|
||||||
line.general_account_id,
|
|
||||||
line.product_uom_id,
|
|
||||||
move_line.ref""", (account.id,))
|
|
||||||
for product_id, amount, account_id, product_uom_id, ref in cr.fetchall():
|
|
||||||
product = product_obj.browse(cr, uid, product_id, context2)
|
|
||||||
|
|
||||||
if product:
|
|
||||||
taxes = product.taxes_id
|
|
||||||
else:
|
|
||||||
taxes = []
|
|
||||||
|
|
||||||
tax = fiscal_pos_obj.map_tax(cr, uid, account.partner_id.property_account_position, taxes)
|
|
||||||
if not account_id:
|
|
||||||
raise osv.except_osv(_("Configuration Error"), _("No income account defined for product '%s'") % product.name)
|
|
||||||
curr_line = {
|
|
||||||
'price_unit': -amount,
|
|
||||||
'quantity': 1.0,
|
|
||||||
'discount': 0.0,
|
|
||||||
'invoice_line_tax_id': [(6,0,tax)],
|
|
||||||
'invoice_id': last_invoice,
|
|
||||||
'name': ref or '' +(product and ' - '+product.name or ''),
|
|
||||||
'product_id': product_id,
|
|
||||||
'uos_id': product_uom_id,
|
|
||||||
'account_id': account_id,
|
|
||||||
'account_analytic_id': account.id
|
|
||||||
}
|
|
||||||
invoice_line_obj.create(cr, uid, curr_line, context=context)
|
|
||||||
|
|
||||||
if not balance_product:
|
|
||||||
raise osv.except_osv(_('Balance product needed'), _('Please fill a Balance product in the wizard'))
|
|
||||||
product = product_obj.browse(cr, uid, balance_product, context=context2)
|
|
||||||
taxes = product.taxes_id
|
|
||||||
tax = fiscal_pos_obj.map_tax(cr, uid, account.partner_id.property_account_position, taxes)
|
|
||||||
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
|
|
||||||
if not account_id:
|
|
||||||
raise osv.except_osv(_("Configuration Error"), _("No income account defined for product '%s'") % product.name)
|
|
||||||
curr_line = {
|
|
||||||
'price_unit': account.amount_max - amount_total,
|
|
||||||
'quantity': 1.0,
|
|
||||||
'discount': 0.0,
|
|
||||||
'invoice_line_tax_id': [(6,0,tax)],
|
|
||||||
'invoice_id': last_invoice,
|
|
||||||
'name': product.name,
|
|
||||||
'product_id': product.id,
|
|
||||||
'uos_id': product.uom_id.id,
|
|
||||||
'account_id': account_id,
|
|
||||||
'account_analytic_id': account.id
|
|
||||||
}
|
|
||||||
invoice_line_obj.create(cr, uid, curr_line, context=context)
|
|
||||||
if account.amount_max < amount_total:
|
|
||||||
invoice_obj.write(cr, uid, [last_invoice], {'type': 'out_refund',}, context=context)
|
|
||||||
cr.execute('update account_analytic_line set invoice_id=%s where invoice_id is null and account_id=%s', (last_invoice, account.id))
|
|
||||||
|
|
||||||
return {
|
|
||||||
'domain': "[('id','in', ["+','.join(map(str,invoices))+"])]",
|
|
||||||
'name': 'Invoices',
|
|
||||||
'view_type': 'form',
|
|
||||||
'view_mode': 'tree,form',
|
|
||||||
'res_model': 'account.invoice',
|
|
||||||
'view_id': False,
|
|
||||||
'context': "{'type':'out_invoice'}",
|
|
||||||
'type': 'ir.actions.act_window',
|
|
||||||
'search_view_id': res['res_id']
|
|
||||||
}
|
|
||||||
|
|
||||||
final_invoice_create()
|
final_invoice_create()
|
||||||
|
|
||||||
|
|
|
@ -27,43 +27,18 @@ from tools.translate import _
|
||||||
## Create an invoice based on selected timesheet lines
|
## Create an invoice based on selected timesheet lines
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
class account_analytic_line(osv.osv):
|
||||||
# TODO: check unit of measure !!!
|
_inherit = "account.analytic.line"
|
||||||
#
|
|
||||||
class hr_timesheet_invoice_create(osv.osv_memory):
|
|
||||||
|
|
||||||
_name = 'hr.timesheet.invoice.create'
|
#
|
||||||
_description = 'Create invoice from timesheet'
|
# data = {
|
||||||
_columns = {
|
# 'date': boolean
|
||||||
'date': fields.boolean('Date', help='The real date of each work will be displayed on the invoice'),
|
# 'time': boolean
|
||||||
'time': fields.boolean('Time spent', help='The time of each work done will be displayed on the invoice'),
|
# 'name': boolean
|
||||||
'name': fields.boolean('Description', help='The detail of each work done will be displayed on the invoice'),
|
# 'price': boolean
|
||||||
'price': fields.boolean('Cost', help='The cost of each work done will be displayed on the invoice. You probably don\'t want to check this'),
|
# 'product': many2one id
|
||||||
'product': fields.many2one('product.product', 'Product', help='Complete this field only if you want to force to use a specific product. Keep empty to use the real product that comes from the cost.'),
|
# }
|
||||||
}
|
def invoice_cost_create(self, cr, uid, ids, data={}, context=None):
|
||||||
|
|
||||||
_defaults = {
|
|
||||||
'date': lambda *args: 1,
|
|
||||||
'name': lambda *args: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
def view_init(self, cr, uid, fields, context=None):
|
|
||||||
"""
|
|
||||||
This function checks for precondition before wizard executes
|
|
||||||
@param self: The object pointer
|
|
||||||
@param cr: the current row, from the database cursor,
|
|
||||||
@param uid: the current user’s ID for security checks,
|
|
||||||
@param fields: List of fields for default value
|
|
||||||
@param context: A standard dictionary for contextual values
|
|
||||||
"""
|
|
||||||
analytic_obj = self.pool.get('account.analytic.line')
|
|
||||||
data = context and context.get('active_ids', [])
|
|
||||||
for analytic in analytic_obj.browse(cr, uid, data, context=context):
|
|
||||||
if analytic.invoice_id:
|
|
||||||
raise osv.except_osv(_('Warning !'), _("Invoice is already linked to some of the analytic line(s)!"))
|
|
||||||
|
|
||||||
def do_create(self, cr, uid, ids, context=None):
|
|
||||||
mod_obj = self.pool.get('ir.model.data')
|
|
||||||
analytic_account_obj = self.pool.get('account.analytic.account')
|
analytic_account_obj = self.pool.get('account.analytic.account')
|
||||||
res_partner_obj = self.pool.get('res.partner')
|
res_partner_obj = self.pool.get('res.partner')
|
||||||
account_payment_term_obj = self.pool.get('account.payment.term')
|
account_payment_term_obj = self.pool.get('account.payment.term')
|
||||||
|
@ -77,11 +52,9 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
invoices = []
|
invoices = []
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
result = mod_obj._get_id(cr, uid, 'account', 'view_account_invoice_filter')
|
|
||||||
data = self.read(cr, uid, ids, [], context=context)[0]
|
|
||||||
|
|
||||||
account_ids = {}
|
account_ids = {}
|
||||||
for line in self.pool.get('account.analytic.line').browse(cr, uid, context['active_ids'], context=context):
|
for line in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):
|
||||||
account_ids[line.account_id.id] = True
|
account_ids[line.account_id.id] = True
|
||||||
|
|
||||||
account_ids = account_ids.keys() #data['accounts']
|
account_ids = account_ids.keys() #data['accounts']
|
||||||
|
@ -127,7 +100,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
"FROM account_analytic_line as line " \
|
"FROM account_analytic_line as line " \
|
||||||
"WHERE account_id = %s " \
|
"WHERE account_id = %s " \
|
||||||
"AND id IN %s AND to_invoice IS NOT NULL " \
|
"AND id IN %s AND to_invoice IS NOT NULL " \
|
||||||
"GROUP BY product_id,to_invoice,product_uom_id", (account.id, tuple(context['active_ids']),))
|
"GROUP BY product_id,to_invoice,product_uom_id", (account.id, tuple(ids),))
|
||||||
|
|
||||||
for product_id, factor_id, qty, uom in cr.fetchall():
|
for product_id, factor_id, qty, uom in cr.fetchall():
|
||||||
product = product_obj.browse(cr, uid, product_id, context2)
|
product = product_obj.browse(cr, uid, product_id, context2)
|
||||||
|
@ -135,7 +108,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
raise osv.except_osv(_('Error'), _('At least one line has no product !'))
|
raise osv.except_osv(_('Error'), _('At least one line has no product !'))
|
||||||
factor_name = ''
|
factor_name = ''
|
||||||
factor = invoice_factor_obj.browse(cr, uid, factor_id, context2)
|
factor = invoice_factor_obj.browse(cr, uid, factor_id, context2)
|
||||||
if not data['product']:
|
if not data.get('product', False):
|
||||||
if factor.customer_name:
|
if factor.customer_name:
|
||||||
factor_name = product.name+' - '+factor.customer_name
|
factor_name = product.name+' - '+factor.customer_name
|
||||||
else:
|
else:
|
||||||
|
@ -148,7 +121,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
ctx.update({'uom':uom})
|
ctx.update({'uom':uom})
|
||||||
if account.pricelist_id:
|
if account.pricelist_id:
|
||||||
pl = account.pricelist_id.id
|
pl = account.pricelist_id.id
|
||||||
price = pro_price_obj.price_get(cr,uid,[pl], data['product'] or product_id, qty or 1.0, account.partner_id.id, context=ctx)[pl]
|
price = pro_price_obj.price_get(cr,uid,[pl], data.get('product', False) or product_id, qty or 1.0, account.partner_id.id, context=ctx)[pl]
|
||||||
else:
|
else:
|
||||||
price = 0.0
|
price = 0.0
|
||||||
|
|
||||||
|
@ -164,7 +137,7 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
'invoice_line_tax_id': [(6,0,tax )],
|
'invoice_line_tax_id': [(6,0,tax )],
|
||||||
'invoice_id': last_invoice,
|
'invoice_id': last_invoice,
|
||||||
'name': factor_name,
|
'name': factor_name,
|
||||||
'product_id': data['product'] or product_id,
|
'product_id': data.get('product',product_id),
|
||||||
'invoice_line_tax_id': [(6,0,tax)],
|
'invoice_line_tax_id': [(6,0,tax)],
|
||||||
'uos_id': uom,
|
'uos_id': uom,
|
||||||
'account_id': account_id,
|
'account_id': account_id,
|
||||||
|
@ -174,37 +147,76 @@ class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
#
|
#
|
||||||
# Compute for lines
|
# Compute for lines
|
||||||
#
|
#
|
||||||
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id IN %s AND product_id=%s and to_invoice=%s ORDER BY account_analytic_line.date", (account.id, tuple(context['active_ids']), product_id, factor_id))
|
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id IN %s AND product_id=%s and to_invoice=%s ORDER BY account_analytic_line.date", (account.id, tuple(ids), product_id, factor_id))
|
||||||
|
|
||||||
line_ids = cr.dictfetchall()
|
line_ids = cr.dictfetchall()
|
||||||
note = []
|
note = []
|
||||||
for line in line_ids:
|
for line in line_ids:
|
||||||
# set invoice_line_note
|
# set invoice_line_note
|
||||||
details = []
|
details = []
|
||||||
if data['date']:
|
if data.get('date', False):
|
||||||
details.append(line['date'])
|
details.append(line['date'])
|
||||||
if data['time']:
|
if data.get('time', False):
|
||||||
if line['product_uom_id']:
|
if line['product_uom_id']:
|
||||||
details.append("%s %s" % (line['unit_amount'], product_uom_obj.browse(cr, uid, [line['product_uom_id']],context2)[0].name))
|
details.append("%s %s" % (line['unit_amount'], product_uom_obj.browse(cr, uid, [line['product_uom_id']],context2)[0].name))
|
||||||
else:
|
else:
|
||||||
details.append("%s" % (line['unit_amount'], ))
|
details.append("%s" % (line['unit_amount'], ))
|
||||||
if data['name']:
|
if data.get('name', False):
|
||||||
details.append(line['name'])
|
details.append(line['name'])
|
||||||
note.append(u' - '.join(map(lambda x: unicode(x) or '',details)))
|
note.append(u' - '.join(map(lambda x: unicode(x) or '',details)))
|
||||||
|
|
||||||
curr_line['note'] = "\n".join(map(lambda x: unicode(x) or '',note))
|
curr_line['note'] = "\n".join(map(lambda x: unicode(x) or '',note))
|
||||||
invoice_line_obj.create(cr, uid, curr_line, context=context)
|
invoice_line_obj.create(cr, uid, curr_line, context=context)
|
||||||
cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id IN %s", (last_invoice, account.id, tuple(context['active_ids'])))
|
cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id IN %s", (last_invoice, account.id, tuple(ids)))
|
||||||
|
|
||||||
invoice_obj.button_reset_taxes(cr, uid, [last_invoice], context)
|
invoice_obj.button_reset_taxes(cr, uid, [last_invoice], context)
|
||||||
|
return invoices
|
||||||
|
|
||||||
|
#
|
||||||
|
# TODO: check unit of measure !!!
|
||||||
|
#
|
||||||
|
|
||||||
|
class hr_timesheet_invoice_create(osv.osv_memory):
|
||||||
|
|
||||||
|
_name = 'hr.timesheet.invoice.create'
|
||||||
|
_description = 'Create invoice from timesheet'
|
||||||
|
_columns = {
|
||||||
|
'date': fields.boolean('Date', help='The real date of each work will be displayed on the invoice'),
|
||||||
|
'time': fields.boolean('Time spent', help='The time of each work done will be displayed on the invoice'),
|
||||||
|
'name': fields.boolean('Description', help='The detail of each work done will be displayed on the invoice'),
|
||||||
|
'price': fields.boolean('Cost', help='The cost of each work done will be displayed on the invoice. You probably don\'t want to check this'),
|
||||||
|
'product': fields.many2one('product.product', 'Product', help='Complete this field only if you want to force to use a specific product. Keep empty to use the real product that comes from the cost.'),
|
||||||
|
}
|
||||||
|
|
||||||
|
_defaults = {
|
||||||
|
'date': lambda *args: 1,
|
||||||
|
'name': lambda *args: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
def view_init(self, cr, uid, fields, context=None):
|
||||||
|
"""
|
||||||
|
This function checks for precondition before wizard executes
|
||||||
|
@param self: The object pointer
|
||||||
|
@param cr: the current row, from the database cursor,
|
||||||
|
@param uid: the current user’s ID for security checks,
|
||||||
|
@param fields: List of fields for default value
|
||||||
|
@param context: A standard dictionary for contextual values
|
||||||
|
"""
|
||||||
|
analytic_obj = self.pool.get('account.analytic.line')
|
||||||
|
data = context and context.get('active_ids', [])
|
||||||
|
for analytic in analytic_obj.browse(cr, uid, data, context=context):
|
||||||
|
if analytic.invoice_id:
|
||||||
|
raise osv.except_osv(_('Warning !'), _("Invoice is already linked to some of the analytic line(s)!"))
|
||||||
|
|
||||||
|
def do_create(self, cr, uid, ids, context=None):
|
||||||
|
data = self.read(cr, uid, ids, [], context=context)[0]
|
||||||
|
invs = self.pool.get('account.analytic.line').invoice_cost_create(cr, uid, context['active_ids'], data, context=context)
|
||||||
mod_obj = self.pool.get('ir.model.data')
|
mod_obj = self.pool.get('ir.model.data')
|
||||||
act_obj = self.pool.get('ir.actions.act_window')
|
act_obj = self.pool.get('ir.actions.act_window')
|
||||||
|
|
||||||
mod_ids = mod_obj.search(cr, uid, [('name', '=', 'action_invoice_tree1')], context=context)[0]
|
mod_ids = mod_obj.search(cr, uid, [('name', '=', 'action_invoice_tree1')], context=context)[0]
|
||||||
res_id = mod_obj.read(cr, uid, mod_ids, ['res_id'], context=context)['res_id']
|
res_id = mod_obj.read(cr, uid, mod_ids, ['res_id'], context=context)['res_id']
|
||||||
act_win = act_obj.read(cr, uid, res_id, [], context=context)
|
act_win = act_obj.read(cr, uid, res_id, [], context=context)
|
||||||
act_win['domain'] = [('id','in',invoices),('type','=','out_invoice')]
|
act_win['domain'] = [('id','in',invs),('type','=','out_invoice')]
|
||||||
act_win['name'] = _('Invoices')
|
act_win['name'] = _('Invoices')
|
||||||
return act_win
|
return act_win
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,50 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<record id="view_hr_timesheet_invoice_create_final" model="ir.ui.view">
|
|
||||||
<field name="name">hr.timesheet.invoice.create.final.form</field>
|
|
||||||
<field name="model">hr.timesheet.invoice.create.final</field>
|
|
||||||
<field name="type">form</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Final invoice for analytic account">
|
|
||||||
<group col="4" colspan="6">
|
|
||||||
<separator string="Do you want details for each line of the invoices ?" colspan="4"/>
|
|
||||||
<field name="date"/>
|
|
||||||
<field name="time"/>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="price"/>
|
|
||||||
<separator string="Invoice Balance amount" colspan="4"/>
|
|
||||||
<field name="balance_product" required="1"/>
|
|
||||||
</group>
|
|
||||||
<separator colspan="4"/>
|
|
||||||
<group col="2" colspan="4">
|
|
||||||
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
|
|
||||||
<button name="do_create" string="Create Invoices" colspan="1" type="object" icon="terp-gtk-go-back-rtl"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="action_hr_timesheet_invoice_create_final" model="ir.actions.act_window">
|
<record id="action_hr_timesheet_invoice_create_final" model="ir.actions.act_window">
|
||||||
<field name="name">Final Invoice</field>
|
<field name="name">Create Invoice</field>
|
||||||
<field name="type">ir.actions.act_window</field>
|
<field name="type">ir.actions.act_window</field>
|
||||||
<field name="res_model">hr.timesheet.invoice.create.final</field>
|
<field name="res_model">hr.timesheet.invoice.create.final</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">form</field>
|
<field name="view_mode">form</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
|
<field name="multi" eval="1"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.values" id="hr_timesheet_invoice_create_final_values">
|
<record model="ir.values" id="hr_timesheet_invoice_create_final_values">
|
||||||
<field name="model_id" ref="model_account_analytic_account" />
|
<field name="model_id" ref="model_account_analytic_account" />
|
||||||
<field name="name">Final Invoice</field>
|
<field name="object" eval="1" />
|
||||||
|
<field name="name">Invoice</field>
|
||||||
<field name="key2">client_action_multi</field>
|
<field name="key2">client_action_multi</field>
|
||||||
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_hr_timesheet_invoice_create_final'))" />
|
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_hr_timesheet_invoice_create_final'))" />
|
||||||
<field name="key">action</field>
|
<field name="key">action</field>
|
||||||
<field name="model">account.analytic.account</field>
|
<field name="model">account.analytic.account</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</data>
|
|
||||||
|
<record id="view_hr_timesheet_invoice_create_final" model="ir.ui.view">
|
||||||
|
<field name="name">hr.timesheet.invoice.create.final.form</field>
|
||||||
|
<field name="model">hr.timesheet.invoice.create.final</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Invoice contract">
|
||||||
|
<group col="4" colspan="6">
|
||||||
|
<separator string="Do you want to display work details on the invoice ?" colspan="4"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="time"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="price"/>
|
||||||
|
<separator string="Force to use a special product" colspan="4" groups="base.group_extended"/>
|
||||||
|
<field name="product" groups="base.group_extended"/>
|
||||||
|
</group>
|
||||||
|
<separator colspan="4"/>
|
||||||
|
<group col="2" colspan="4">
|
||||||
|
<button special="cancel" string="Cancel" icon='gtk-cancel'/>
|
||||||
|
<button name="do_create" string="Create Invoice" colspan="1" type="object" icon="terp-gtk-go-back-rtl"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
<newline/>
|
<newline/>
|
||||||
<separator colspan="4"/>
|
<separator colspan="4"/>
|
||||||
<group col="9" colspan="8">
|
<group col="9" colspan="8">
|
||||||
<field name="state" widget="statusbar" statusbar_visible="open,close" statusbar_colors='{"pending":"blue"}' select="1" readonly="1"/>
|
<field name="state" widget="statusbar" statusbar_visible="open,close" statusbar_colors='{"pending":"blue"}' select="1" readonly="1"/>
|
||||||
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
||||||
<button name="set_template" string="Set as Template" type="object" states="open" icon="gtk-convert" groups="base.group_extended"/>
|
<button name="set_template" string="Set as Template" type="object" states="open" icon="gtk-convert" groups="base.group_extended"/>
|
||||||
<button name="set_open" string="Reactivate Project" type="object" states="pending,cancelled,close" icon="gtk-ok"/>
|
<button name="set_open" string="Reactivate Project" type="object" states="pending,cancelled,close" icon="gtk-ok"/>
|
||||||
|
|
|
@ -34,7 +34,7 @@ the Timesheet line entries for particular date and particular user with the eff
|
||||||
'author': 'OpenERP SA',
|
'author': 'OpenERP SA',
|
||||||
'website': 'http://www.openerp.com',
|
'website': 'http://www.openerp.com',
|
||||||
'images': ['images/invoice_task_work.jpeg', 'images/my_timesheet.jpeg', 'images/working_hour.jpeg'],
|
'images': ['images/invoice_task_work.jpeg', 'images/my_timesheet.jpeg', 'images/working_hour.jpeg'],
|
||||||
'depends': ['project', 'hr_timesheet_sheet', 'hr_timesheet_invoice'],
|
'depends': ['project', 'hr_timesheet_sheet', 'hr_timesheet_invoice', 'account_analytic_analysis'],
|
||||||
'init_xml': ['project_timesheet_data.xml'],
|
'init_xml': ['project_timesheet_data.xml'],
|
||||||
'update_xml': ["security/ir.model.access.csv","process/project_timesheet_process.xml", "report/task_report_view.xml", "project_timesheet_view.xml"],
|
'update_xml': ["security/ir.model.access.csv","process/project_timesheet_process.xml", "report/task_report_view.xml", "project_timesheet_view.xml"],
|
||||||
'demo_xml': ["project_timesheet_demo.xml"],
|
'demo_xml': ["project_timesheet_demo.xml"],
|
||||||
|
|
|
@ -105,8 +105,9 @@ the project form.</field>
|
||||||
<!--
|
<!--
|
||||||
Time Tracking menu in project Management
|
Time Tracking menu in project Management
|
||||||
-->
|
-->
|
||||||
<menuitem icon="terp-project" id="base.menu_main_pm" name="Project" sequence="10"/>
|
|
||||||
<menuitem id="menu_project_working_hours" parent="base.menu_project_management_time_tracking" action="hr_timesheet.act_hr_timesheet_line_evry1_all_form"/>
|
<menuitem id="menu_project_working_hours" parent="base.menu_project_management_time_tracking" action="hr_timesheet.act_hr_timesheet_line_evry1_all_form"/>
|
||||||
|
|
||||||
|
<menuitem id="menu_invoicing" name="Billing" parent="base.menu_main_pm" sequence="4"/>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</openerp>
|
</openerp>
|
||||||
|
|
|
@ -489,8 +489,8 @@
|
||||||
src_model="product.product"
|
src_model="product.product"
|
||||||
groups="base.group_sale_salesman"/>
|
groups="base.group_sale_salesman"/>
|
||||||
|
|
||||||
<menuitem id="menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5" groups="-base.group_extended"/>
|
<menuitem id="base.menu_invoiced" name="Invoicing" parent="base.menu_base_partner" sequence="5" groups="-base.group_extended"/>
|
||||||
<menuitem id="menu_invoicing_sales_order_lines" parent="menu_invoiced" action="action_order_line_tree2" sequence="2" groups="base.group_no_one"/>
|
<menuitem id="menu_invoicing_sales_order_lines" parent="base.menu_invoiced" action="action_order_line_tree2" sequence="2" groups="base.group_no_one"/>
|
||||||
|
|
||||||
<!-- configartion view -->
|
<!-- configartion view -->
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue