bzr revid: fp@tinyerp.com-20081027172321-brgqo5hdnjqqhtx8
This commit is contained in:
Fabien Pinckaers 2008-10-27 18:23:21 +01:00
parent 68c1ddab01
commit 529997384d
5 changed files with 95 additions and 133 deletions

View File

@ -87,21 +87,22 @@ class account_analytic_account(osv.osv):
WHERE account_analytic_account.id IN (%s) \
AND account_analytic_line.invoice_id is null \
AND account_analytic_line.to_invoice IS NOT NULL \
and account_analytic_journal.type in ('purchase','general') \
GROUP BY account_analytic_account.id;"""%acc_set)
for account_id, sum in cr.fetchall():
res[account_id] = round(sum,2)
# Expense amount and purchase invoice
acc_set = ",".join(map(str, ids2))
cr.execute ("select account_analytic_line.account_id, sum(amount) \
from account_analytic_line \
join account_analytic_journal \
on account_analytic_line.journal_id = account_analytic_journal.id \
where account_analytic_line.account_id IN (%s) \
and account_analytic_journal.type = 'purchase' \
GROUP BY account_analytic_line.account_id;"%acc_set)
for account_id, sum in cr.fetchall():
res2[account_id] = round(sum,2)
#acc_set = ",".join(map(str, ids2))
#cr.execute ("select account_analytic_line.account_id, sum(amount) \
# from account_analytic_line \
# join account_analytic_journal \
# on account_analytic_line.journal_id = account_analytic_journal.id \
# where account_analytic_line.account_id IN (%s) \
# and account_analytic_journal.type = 'purchase' \
# GROUP BY account_analytic_line.account_id;"%acc_set)
#for account_id, sum in cr.fetchall():
# res2[account_id] = round(sum,2)
for obj_id in ids:
res.setdefault(obj_id, 0.0)
res2.setdefault(obj_id, 0.0)
@ -338,7 +339,7 @@ class account_analytic_account(osv.osv):
if account.ca_invoiced == 0:
res[account.id]=0.0
elif account.real_margin <> 0.0:
res[account.id] = (account.ca_invoiced / account.real_margin) * 100
res[account.id] = -(account.real_margin / account.total_cost) * 100
else:
res[account.id] = 0.0
for id in ids:
@ -398,19 +399,19 @@ class account_analytic_account(osv.osv):
'ca_invoiced': fields.function(_ca_invoiced_calc, method=True, type='float', string='Invoiced Amount', help="Total customer invoiced amount for this account."),
'total_cost': fields.function(_total_cost_calc, method=True, type='float', string='Total Costs', help="Total of costs for this account. It includes real costs (from invoices) and indirect costs, like time spent on timesheets."),
'ca_to_invoice': fields.function(_ca_to_invoice_calc, method=True, type='float', string='Uninvoiced Amount', help="If invoice from analytic account, the remaining amount you can invoice to the customer based on the total costs."),
'ca_theorical': fields.function(_ca_theorical_calc, method=True, type='float', string='Theorical Revenue', help="Based on the costs you had on the project, what would have been the revenue of all these costs have been invoiced at the normal sale price provided by the pricelist."),
'hours_quantity': fields.function(_hours_quantity_calc, method=True, type='float', string='Hours Tot', help="Number of hours on spent on the analytic account (from timesheet). It computes on all journal of type 'general'."),
'ca_theorical': fields.function(_ca_theorical_calc, method=True, type='float', string='Theorical Revenue', help="Based on the costs you had on the project, what would have been the revenue if all these costs have been invoiced at the normal sale price provided by the pricelist."),
'hours_quantity': fields.function(_hours_quantity_calc, method=True, type='float', string='Hours Tot', help="Number of hours you spent on the analytic account (from timesheet). It computes on all journal of type 'general'."),
'last_invoice_date': fields.function(_last_invoice_date_calc, method=True, type='date', string='Last Invoice Date', help="Date of the last invoice created for this analytic account."),
'last_worked_invoiced_date': fields.function(_last_worked_invoiced_date_calc, method=True, type='date', string='Last Invoiced Worked Date', help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
'last_worked_date': fields.function(_last_worked_date_calc, method=True, type='date', string='Last Worked Date', help="Date of the latest work done on this account."),
'last_worked_invoiced_date': fields.function(_last_worked_invoiced_date_calc, method=True, type='date', string='Date of Last Invoiced Cost', help="If invoice from the costs, this is the date of the latest work or cost that have been invoiced."),
'last_worked_date': fields.function(_last_worked_date_calc, method=True, type='date', string='Date of Last Cost/Work', help="Date of the latest work done on this account."),
'hours_qtt_non_invoiced': fields.function(_hours_qtt_non_invoiced_calc, method=True, type='float', string='Uninvoiced Hours', help="Number of hours (from journal of type 'general') that can be invoiced if you invoice based on analytic account."),
'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, method=True, type='float', string='Invoiced Hours', help="Number of hours that already have invoiced. If you don't invoice based on costs, it's the number of hours spent. If you invoice based on hours, it's the hours that have been invoiced."),
'remaining_hours': fields.function(_remaining_hours_calc, method=True, type='float', string='Remaining Hours', help="Computed using the forumla: Maximum Quantity - Hours Tot."),
'remaining_ca': fields.function(_remaining_ca_calc, method=True, type='float', string='Remaining Revenue', help="If you invoice based on costs, this is the revenue you will invoice to the customer when you will launch the invoicing wizard."),
'hours_qtt_invoiced': fields.function(_hours_qtt_invoiced_calc, method=True, type='float', string='Invoiced Hours', help="Number of hours that can be invoiced plus those that already have been invoiced."),
'remaining_hours': fields.function(_remaining_hours_calc, method=True, type='float', string='Remaining Hours', help="Computed using the formula: Maximum Quantity - Hours Tot."),
'remaining_ca': fields.function(_remaining_ca_calc, method=True, type='float', string='Remaining Revenue', help="Computed using the formula: Max Invoice Price - Invoiced Amount."),
'revenue_per_hour': fields.function(_revenue_per_hour_calc, method=True, type='float', string='Revenue per Hours (real)', help="Computed using the formula: Invoiced Amount / Hours Tot."),
'real_margin': fields.function(_real_margin_calc, method=True, type='float', string='Real Margin', help="Computed using the formula: Invoiced Amount - Total Costs."),
'theorical_margin': fields.function(_theorical_margin_calc, method=True, type='float', string='Theorical Margin', help="Computed using the formula: (Theorical Revenue / Total Costs) * 100."),
'real_margin_rate': fields.function(_real_margin_rate_calc, method=True, type='float', string='Real Margin Rate (%)', help="Computes using the formula: (Invoiced Amount / Total Costs) * 100."),
'theorical_margin': fields.function(_theorical_margin_calc, method=True, type='float', string='Theorical Margin', help="Computed using the formula: Theorial Revenue - Total Costs"),
'real_margin_rate': fields.function(_real_margin_rate_calc, method=True, type='float', string='Real Margin Rate (%)', help="Computes using the formula: (Real Margin / Total Costs) * 100."),
'month_ids': fields.function(_month, method=True, type='many2many', relation='account_analytic_analysis.summary.month', string='Month'),
'user_ids': fields.function(_user, method=True, type="many2many", relation='account_analytic_analysis.summary.user', string='User'),
}
@ -437,8 +438,7 @@ class account_analytic_account_summary_user(osv.osv):
cr.execute('SELECT id, unit_amount ' \
'FROM account_analytic_analysis_summary_user ' \
'WHERE account_id in (%s) ' \
'AND "user" in (%s) ' % \
(acc_set, user_set))
'AND "user" in (%s) ' % (acc_set, user_set))
for sum_id, unit_amount in cr.fetchall():
res[sum_id] = unit_amount
for obj_id in ids:

View File

@ -33,8 +33,8 @@
<field name="revenue_per_hour"/>
<field name="real_margin"/>
<field name="theorical_margin"/>
<field name="real_margin_rate"/>
<field name="theorical_margin"/>
<separator colspan="4" string="Key dates"/>
<field name="last_invoice_date"/>

View File

@ -2,7 +2,7 @@
<openerp>
<data>
<wizard id="hr_timesheet_invoice_create" model="account.analytic.line" name="hr.timesheet.invoice.create" string="Invoice analytic lines"/>
<wizard id="hr_timesheet_final_invoice_create" model="account.analytic.account" name="hr.timesheet.final.invoice.create" string="Final invoices"/>
<wizard id="hr_timesheet_final_invoice_create" model="account.analytic.account" name="hr.timesheet.final.invoice.create" string="Final Invoice"/>
</data>
</openerp>

View File

@ -42,10 +42,7 @@ from tools.translate import _
#
class final_invoice_create(wizard.interface):
def _get_defaults(self, cr, uid, data, context):
if not data['ids']:
return {}
account = pooler.get_pool(cr.dbname).get('account.analytic.account').browse(cr, uid, data['ids'], context)[0]
return {'use_amount_max': bool(account.amount_max)}
return {}
def _do_create(self, cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
@ -93,63 +90,26 @@ class final_invoice_create(wizard.interface):
"WHERE account_id = %d " \
"AND to_invoice IS NOT NULL " \
"GROUP BY product_id, to_invoice", (account.id,))
for product_id,factor_id,qty in cr.fetchall():
product = pool.get('product.product').browse(cr, uid, product_id, context2)
factor_name = ''
factor = pool.get('hr_timesheet_invoice.factor').browse(cr, uid, factor_id, context2)
if factor.customer_name:
factor_name = product.name+' - '+factor.customer_name
else:
factor_name = product.name
if account.pricelist_id:
pl = account.pricelist_id.id
price = pool.get('product.pricelist').price_get(cr,uid,[pl], product_id, qty or 1.0, account.partner_id.id)[pl]
else:
price = 0.0
taxes = product.taxes_id
tax = self.pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
curr_line = {
'price_unit': price,
'quantity': qty,
'discount':factor.factor,
'invoice_line_tax_id': [(6,0,tax )],
'invoice_id': last_invoice,
'name': factor_name,
'product_id': product_id,
'uos_id': product.uom_id.id,
'account_id': account_id,
'account_analytic_id': account.id,
}
amount_total += round((price * ( 1.0 - (factor.factor or 0.0)/100.0)), 2) * qty
#
# Compute for lines
#
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %d AND product_id=%d and to_invoice=%d" % (account.id, product_id, factor_id))
line_ids = cr.dictfetchall()
note = []
for line in line_ids:
# set invoice_line_note
details = []
if data['form']['date']:
details.append(line['date'])
if data['form']['time']:
details.append("%s %s" % (line['unit_amount'], pool.get('product.uom').browse(cr, uid, [line['product_uom_id']])[0].name))
if data['form']['name']:
details.append(line['name'])
#if data['form']['price']:
# details.append(abs(line['amount']))
note.append(' - '.join(map(str,details)))
curr_line['note'] = "\n".join(map(str,note))
pool.get('account.invoice.line').create(cr, uid, curr_line)
cr.execute("update account_analytic_line set invoice_id=%d WHERE account_id = %d and invoice_id is null" % (last_invoice,account.id,))
cr.execute("SELECT line.product_id, sum(line.amount), line.account_id, line.product_uom_id, move_line.ref FROM account_analytic_line as line, account_move_line as move_line WHERE line.account_id = %d AND line.move_id IS NOT NULL AND move_line.id = line.move_id GROUP BY line.product_id, line.account_id, line.product_uom_id, move_line.ref" % (account.id))
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 = %d 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 = pool.get('product.product').browse(cr, uid, product_id, context2)
@ -158,7 +118,7 @@ class final_invoice_create(wizard.interface):
else:
taxes = []
tax = self.pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
tax = pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
curr_line = {
'price_unit': -amount,
'quantity': 1.0,
@ -169,33 +129,33 @@ class final_invoice_create(wizard.interface):
'product_id': product_id,
'uos_id': product_uom_id,
'account_id': account_id,
'account_analytic_id': account.id
}
pool.get('account.invoice.line').create(cr, uid, curr_line)
if data['form']['use_amount_max']:
if abs(account.amount_max - amount_total) > data['form']['balance_amount'] :
if not data['form']['balance_product']:
raise wizard.except_wizard(_('Balance product needed'), _('Please fill a Balance product in the wizard'))
product = pool.get('product.product').browse(cr, uid, data['form']['balance_product'], context2)
if not data['form']['balance_product']:
raise wizard.except_wizard(_('Balance product needed'), _('Please fill a Balance product in the wizard'))
product = pool.get('product.product').browse(cr, uid, data['form']['balance_product'], context2)
taxes = product.taxes_id
tax = self.pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
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,
}
pool.get('account.invoice.line').create(cr, uid, curr_line)
if account.amount_max < amount_total:
pool.get('account.invoice').write(cr, uid, [last_invoice], {'type': 'out_refund',})
taxes = product.taxes_id
tax = pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
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
}
pool.get('account.invoice.line').create(cr, uid, curr_line)
if account.amount_max < amount_total:
pool.get('account.invoice').write(cr, uid, [last_invoice], {'type': 'out_refund',})
cr.execute('update account_analytic_line set invoice_id=%d where invoice_id is null and account_id=%d', (last_invoice, account.id))
return {
'domain': "[('id','in', ["+','.join(map(str,invoices))+"])]",
@ -217,19 +177,15 @@ class final_invoice_create(wizard.interface):
<field name="name"/>
<field name="price"/>
<separator string="Invoice Balance amount" colspan="4"/>
<field name="use_amount_max"/>
<field name="balance_amount"/>
<field name="balance_product"/>
<field name="balance_product" required="1"/>
</form>"""
_create_fields = {
'date': {'string':'Date', 'type':'boolean'},
'time': {'string':'Time spent', 'type':'boolean'},
'name': {'string':'Name of entry', 'type':'boolean'},
'price': {'string':'Cost', 'type':'boolean'},
'use_amount_max': {'string':'Use Max. Invoice Price', 'type':'boolean'},
'balance_amount': {'string':'Balance amount', 'type': 'float'},
'balance_product': {'string':'Balance product', 'type': 'many2one', 'relation':'product.product'},
'date': {'string':'Date', 'type':'boolean', 'help':"Display date in the history of works"},
'time': {'string':'Time spent', 'type':'boolean', 'help':"Display time in the history of works"},
'name': {'string':'Name of entry', 'type':'boolean', 'help':"Display detail of work in the invoice line."},
'price': {'string':'Cost', 'type':'boolean', 'help':"Display cost of the item you reinvoice"},
'balance_product': {'string':'Balance product', 'type': 'many2one', 'relation':'product.product', 'help':"The product that will be used to invoice the remaining amount."},
}
states = {

View File

@ -113,7 +113,7 @@ class invoice_create(wizard.interface):
price = 0.0
taxes = product.taxes_id
tax = self.pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
tax = pool.get('account.fiscal.position').map_tax(cr, uid, account.partner_id, taxes)
account_id = product.product_tmpl_id.property_account_income.id or product.categ_id.property_account_income_categ.id
curr_line = {
@ -167,24 +167,30 @@ class invoice_create(wizard.interface):
_create_form = """<?xml version="1.0"?>
<form title="Invoice on analytic entries">
<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="Choose accounts you want to invoice" colspan="4"/>
<field name="accounts" colspan="4"/>
<separator string="Choose a product for intermediary invoice" colspan="4"/>
<field name="product"/>
<notebook>
<page string="Invoicing Data">
<separator string="Do you want to show details of work in invoice ?" colspan="4"/>
<field name="date"/>
<field name="time"/>
<field name="name"/>
<field name="price"/>
<separator string="Force to use a specific product" colspan="4"/>
<field name="product"/>
</page>
<page string="Filter on Accounts" groups="base.group_extended">
<separator string="Choose accounts you want to invoice" colspan="4"/>
<field name="accounts" colspan="4" nolabel="1"/>
</page>
</notebook>
</form>"""
_create_fields = {
'accounts': {'string':'Analytic Accounts', 'type':'many2many', 'required':'true', 'relation':'account.analytic.account'},
'date': {'string':'Date', 'type':'boolean'},
'time': {'string':'Time spent', 'type':'boolean'},
'name': {'string':'Name of entry', 'type':'boolean'},
'price': {'string':'Cost', 'type':'boolean'},
'product': {'string':'Product', 'type':'many2one', 'relation': 'product.product'},
'date': {'string':'Date', 'type':'boolean', 'help':'The real date of each work will be displayed on the invoice'},
'time': {'string':'Time spent', 'type':'boolean', 'help':'The time of each work done will be displayed on the invoice'},
'name': {'string':'Name of entry', 'type':'boolean', 'help':'The detail of each work done will be displayed on the invoice'},
'price': {'string':'Cost', 'type':'boolean', 'help':'The cost of each work done will be displayed on the invoice. You probably don\'t want to check this.'},
'product': {'string':'Product', 'type':'many2one', 'relation': '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."},
}
states = {