mirror of
https://github.com/OCA/contract.git
synced 2025-02-13 17:57:24 +02:00
[FIX] python formatting and cleanings
This commit is contained in:
@@ -20,31 +20,35 @@
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
"name" : "Project Hours Blocks Management",
|
||||
"description" : """
|
||||
"name": "Project Hours Blocks Management",
|
||||
"description": """
|
||||
Project Hours Blocks Management
|
||||
===============================
|
||||
|
||||
This module allows you to handle hours blocks, to follow for example the user support contracts.
|
||||
This means, you sell a product of type "hours block" then you input the spent hours on the hours block and
|
||||
This module allows you to handle hours blocks,
|
||||
to follow for example the user support contracts.
|
||||
This means, you sell a product of type "hours block"
|
||||
then you input the spent hours on the hours block and
|
||||
you can track and follow how much has been used.
|
||||
|
||||
""",
|
||||
"version" : "1.2",
|
||||
"author" : "Camptocamp",
|
||||
"category" : "Generic Modules/Projects & Services",
|
||||
"version": "1.3",
|
||||
"author": "Camptocamp",
|
||||
"license": 'AGPL-3',
|
||||
"category": "Generic Modules/Projects & Services",
|
||||
"website": "http://www.camptocamp.com",
|
||||
"depends" : [
|
||||
"account",
|
||||
"hr_timesheet_invoice",
|
||||
"analytic"
|
||||
],
|
||||
"init_xml" : [],
|
||||
"update_xml" : [
|
||||
"hours_block_view.xml",
|
||||
"hours_block_menu.xml",
|
||||
"report.xml",
|
||||
"security/hours_block_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
"depends": [
|
||||
"account",
|
||||
"hr_timesheet_invoice",
|
||||
"analytic"
|
||||
],
|
||||
"data": [
|
||||
"hours_block_view.xml",
|
||||
"hours_block_menu.xml",
|
||||
"report.xml",
|
||||
"security/hours_block_security.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
|
||||
@@ -19,92 +19,75 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import string
|
||||
|
||||
from osv import osv, fields
|
||||
import netsvc
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
|
||||
############################################################################
|
||||
## Add hours blocks on invoice
|
||||
############################################################################
|
||||
|
||||
class AccountHoursBlock(osv.osv):
|
||||
class AccountHoursBlock(orm.Model):
|
||||
_name = "account.hours.block"
|
||||
|
||||
def _get_last_action(self, cr, uid, ids, name, arg, context=None):
|
||||
"""TODO"""
|
||||
context = context or {}
|
||||
""" Return the last analytic line date for an invoice"""
|
||||
res = {}
|
||||
for block in self.browse(cr, uid, ids):
|
||||
for block in self.browse(cr, uid, ids, context=context):
|
||||
cr.execute("SELECT max(al.date) FROM account_analytic_line AS al"
|
||||
" WHERE al.invoice_id = %s", (block.invoice_id.id,))
|
||||
fetch_res = cr.fetchone()
|
||||
if fetch_res:
|
||||
date = fetch_res[0]
|
||||
else:
|
||||
date = False
|
||||
res[block.id] = date
|
||||
res[block.id] = fetch_res[0] if fetch_res else False
|
||||
return res
|
||||
|
||||
def _compute_hours(self, cr, uid, ids, fields, args, context=None):
|
||||
"""Return a dict of [id][fields]"""
|
||||
context = context or {}
|
||||
if not isinstance(ids, list):
|
||||
ids=[ids]
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
result = {}
|
||||
aal_obj = self.pool.get('account.analytic.line')
|
||||
for block in self.browse(cr,uid,ids):
|
||||
result[block.id] = {'amount_hours_block' : 0.0,
|
||||
'amount_hours_block_done' : 0.0,
|
||||
'amount_hours_block_delta' : 0.0}
|
||||
for block in self.browse(cr, uid, ids, context=context):
|
||||
result[block.id] = {'amount_hours_block': 0.0,
|
||||
'amount_hours_block_done': 0.0}
|
||||
# Compute hours bought
|
||||
for line in block.invoice_id.invoice_line:
|
||||
hours_bought = 0.0
|
||||
if line.product_id:
|
||||
## We will now calculate the product_quantity
|
||||
# We will now calculate the product_quantity
|
||||
factor = line.uos_id.factor
|
||||
if factor == 0.0:
|
||||
factor = 1.0
|
||||
amount = line.quantity
|
||||
hours_bought += (amount / factor)
|
||||
result[block.id]['amount_hours_block'] += hours_bought
|
||||
|
||||
# Compute hours spent
|
||||
hours_used = 0.0
|
||||
# Get ids of analytic line generated from timesheet associated to current block
|
||||
# Get ids of analytic line generated from
|
||||
# timesheet associated to the current block
|
||||
cr.execute("SELECT al.id "
|
||||
" FROM account_analytic_line AS al,account_analytic_journal AS aj"
|
||||
" WHERE aj.id = al.journal_id AND"
|
||||
" aj.type='general' AND"
|
||||
" al.invoice_id = %s", (block.invoice_id.id,))
|
||||
res2 = cr.fetchall()
|
||||
if res2:
|
||||
ids2 = [x[0] for x in res2]
|
||||
else:
|
||||
ids2 = []
|
||||
for line in aal_obj.browse(cr, uid, ids2, context):
|
||||
if line.product_uom_id:
|
||||
"FROM account_analytic_line AS al, "
|
||||
" account_analytic_journal AS aj "
|
||||
"WHERE aj.id = al.journal_id "
|
||||
"AND aj.type = 'general' "
|
||||
"AND al.invoice_id = %s", (block.invoice_id.id,))
|
||||
res_line_ids = cr.fetchall()
|
||||
line_ids = [l[0] for l in res_line_ids] if res_line_ids else []
|
||||
for line in aal_obj.browse(cr, uid, line_ids, context=context):
|
||||
factor = 1.0
|
||||
if line.product_uom_id and line.product_uom_id.factor != 0.0:
|
||||
factor = line.product_uom_id.factor
|
||||
if factor == 0.0:
|
||||
factor = 1.0
|
||||
else:
|
||||
factor = 1.0
|
||||
factor_invoicing = 1.0
|
||||
if line.to_invoice and line.to_invoice.factor != 0.0:
|
||||
factor_invoicing = 1.0 - line.to_invoice.factor / 100
|
||||
factor_invoicing = 1.0 - line.to_invoice.factor / 100
|
||||
hours_used += ((line.unit_amount / factor) * factor_invoicing)
|
||||
result[block.id]['amount_hours_block_done'] = hours_used
|
||||
return result
|
||||
|
||||
def _compute_amount(self, cr, uid, ids, fields, args, context):
|
||||
def _compute_amount(self, cr, uid, ids, fields, args, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
result = {}
|
||||
aal_obj = self.pool.get('account.analytic.line')
|
||||
pricelist_obj = self.pool.get('product.pricelist')
|
||||
for block in self.browse(cr,uid,ids):
|
||||
for block in self.browse(cr, uid, ids, context=context):
|
||||
result[block.id] = {'amount_hours_block' : 0.0,
|
||||
'amount_hours_block_done' : 0.0,
|
||||
'amount_hours_block_delta' : 0.0}
|
||||
'amount_hours_block_done' : 0.0}
|
||||
|
||||
# Compute amount bought
|
||||
for line in block.invoice_id.invoice_line:
|
||||
@@ -125,95 +108,193 @@ class AccountHoursBlock(osv.osv):
|
||||
" WHERE aj.id = al.journal_id"
|
||||
" AND aj.type='general'"
|
||||
" AND al.invoice_id = %s", (block.invoice_id.id,))
|
||||
res2 = cr.fetchall()
|
||||
if res2:
|
||||
ids2 = [x[0] for x in res2]
|
||||
else:
|
||||
ids2 = []
|
||||
res_line_ids = cr.fetchall()
|
||||
line_ids = [l[0] for l in res_line_ids] if res_line_ids else []
|
||||
total_amount = 0.0
|
||||
for line in aal_obj.browse(cr, uid, ids2, context):
|
||||
for line in aal_obj.browse(cr, uid, line_ids, context=context):
|
||||
factor_invoicing = 1.0
|
||||
if line.to_invoice and line.to_invoice.factor != 0.0:
|
||||
factor_invoicing = 1.0 - line.to_invoice.factor / 100
|
||||
factor_invoicing = 1.0 - line.to_invoice.factor / 100
|
||||
|
||||
ctx = {'uom': line.product_uom_id.id}
|
||||
amount = pricelist_obj.price_get(cr, uid,
|
||||
[line.account_id.pricelist_id.id],
|
||||
line.product_id.id,
|
||||
line.unit_amount or 1.0,
|
||||
line.account_id.partner_id.id or False,
|
||||
ctx)[line.account_id.pricelist_id.id]
|
||||
ctx = dict(context, uom=line.product_uom_id.id)
|
||||
amount = pricelist_obj.price_get(
|
||||
cr, uid,
|
||||
[line.account_id.pricelist_id.id],
|
||||
line.product_id.id,
|
||||
line.unit_amount or 1.0,
|
||||
line.account_id.partner_id.id or False,
|
||||
ctx)[line.account_id.pricelist_id.id]
|
||||
total_amount += amount * line.unit_amount * factor_invoicing
|
||||
result[block.id]['amount_hours_block_done'] += total_amount
|
||||
|
||||
return result
|
||||
|
||||
def _compute(self, cr, uid, ids, fields, args, context):
|
||||
def _compute(self, cr, uid, ids, fields, args, context=None):
|
||||
result = {}
|
||||
block_per_types = {}
|
||||
for block in self.browse(cr, uid, ids, context=context):
|
||||
if not block.type in block_per_types.keys():
|
||||
block_per_types[block.type] = []
|
||||
block_per_types[block.type].append(block.id)
|
||||
block_per_types.setdefault(block.type, []).append(block.id)
|
||||
|
||||
for block_type in block_per_types:
|
||||
if block_type:
|
||||
func = getattr(self, "_compute_%s" % (block_type,))
|
||||
result.update(func(cr, uid, ids, fields, args, context))
|
||||
func = getattr(self, "_compute_%s" % block_type)
|
||||
result.update(func(cr, uid, ids, fields, args, context=context))
|
||||
|
||||
for block in result:
|
||||
result[block]['amount_hours_block_delta'] = \
|
||||
result[block]['amount_hours_block'] - result[block]['amount_hours_block_done']
|
||||
result[block]['amount_hours_block'] - \
|
||||
result[block]['amount_hours_block_done']
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'amount_hours_block': fields.function(_compute, method=True, type='float', string='Quantity /Amount bought', store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Amount bought by the customer. This amount is expressed in the base UoM (factor=1.0)"),
|
||||
'amount_hours_block_done': fields.function(_compute, method=True, type='float', string='Quantity / Amount used', store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Amount done by the staff. This amount is expressed in the base UoM (factor=1.0)"),
|
||||
'amount_hours_block_delta': fields.function(_compute, method=True, type='float', string='Difference', store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Difference between bought and used. This amount is expressed in the base UoM (factor=1.0)"),
|
||||
'last_action_date': fields.function(_get_last_action, method=True, type='date', string='Last action date',
|
||||
help="Date of the last analytic line linked to the invoice related to this block hours."),
|
||||
'amount_hours_block': fields.function(
|
||||
_compute,
|
||||
type='float',
|
||||
string='Quantity / Amount bought',
|
||||
store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Amount bought by the customer. "
|
||||
"This amount is expressed in the base Unit of Measure "
|
||||
"(factor=1.0)"),
|
||||
'amount_hours_block_done': fields.function(
|
||||
_compute,
|
||||
type='float',
|
||||
string='Quantity / Amount used',
|
||||
store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Amount done by the staff. "
|
||||
"This amount is expressed in the base Unit of Measure "
|
||||
"(factor=1.0)"),
|
||||
'amount_hours_block_delta': fields.function(
|
||||
_compute,
|
||||
type='float',
|
||||
string='Difference',
|
||||
store=True,
|
||||
multi='amount_hours_block_delta',
|
||||
help="Difference between bought and used. "
|
||||
"This amount is expressed in the base Unit of Measure "
|
||||
"(factor=1.0)"),
|
||||
'last_action_date': fields.function(
|
||||
_get_last_action,
|
||||
type='date',
|
||||
string='Last action date',
|
||||
help="Date of the last analytic line linked to the invoice "
|
||||
"related to this block hours."),
|
||||
'close_date': fields.date('Closed Date'),
|
||||
'invoice_id': fields.many2one('account.invoice', 'Invoice', ondelete='cascade', required=True),
|
||||
'type': fields.selection([('hours','Hours'), ('amount','Amount')], 'Type of Block',
|
||||
required=True, help="Choose if you want a time or amount base block."),
|
||||
'invoice_id': fields.many2one(
|
||||
'account.invoice',
|
||||
'Invoice',
|
||||
ondelete='cascade',
|
||||
required=True),
|
||||
'type': fields.selection(
|
||||
[('hours','Hours'),
|
||||
('amount','Amount')],
|
||||
string='Type of Block',
|
||||
required=True,
|
||||
help="The block is based on the quantity of hours "
|
||||
"or on the amount."),
|
||||
|
||||
# Invoices related infos
|
||||
'date_invoice': fields.related('invoice_id', 'date_invoice', type="date", string="Invoice Date", store=True, readonly=True),
|
||||
'user_id': fields.related('invoice_id', 'user_id', type="many2one", relation="res.users", string="Salesman", store=True, readonly=True),
|
||||
'partner_id': fields.related('invoice_id', 'partner_id', type="many2one", relation="res.partner", string="Partner", store=True, readonly=True),
|
||||
'name': fields.related('invoice_id', 'name', type="char",size=64, string="Description", store=True,readonly=True),
|
||||
'number': fields.related('invoice_id', 'number', type="char",size=64, string="Number", store=True,readonly=True),
|
||||
'journal_id': fields.related('invoice_id', 'journal_id', type="many2one", relation="account.journal", string="Journal", store=True,readonly=True),
|
||||
'period_id': fields.related('invoice_id', 'period_id', type="many2one", relation="account.period", string="Period", store=True,readonly=True),
|
||||
'company_id': fields.related('invoice_id', 'company_id', type="many2one", relation="res.company", string="Company", store=True,readonly=True),
|
||||
'currency_id': fields.related('invoice_id', 'currency_id', type="many2one", relation="res.currency", string="Currency", store=True,readonly=True),
|
||||
'residual': fields.related('invoice_id', 'residual', type="float", string="Residual", store=True,readonly=True),
|
||||
'amount_total': fields.related('invoice_id', 'amount_total', type="float", string="Total", store=True,readonly=True),
|
||||
'state':fields.related('invoice_id','state',
|
||||
type='selection',
|
||||
selection=[
|
||||
('draft','Draft'),
|
||||
('proforma','Pro-forma'),
|
||||
('proforma2','Pro-forma'),
|
||||
('open','Open'),
|
||||
('paid','Paid'),
|
||||
('cancel','Cancelled')
|
||||
],
|
||||
string='State', readonly=True, store=True),
|
||||
'date_invoice': fields.related(
|
||||
'invoice_id', 'date_invoice',
|
||||
type="date",
|
||||
string="Invoice Date",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'user_id': fields.related(
|
||||
'invoice_id', 'user_id',
|
||||
type="many2one",
|
||||
relation="res.users",
|
||||
string="Salesman",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'partner_id': fields.related(
|
||||
'invoice_id', 'partner_id',
|
||||
type="many2one",
|
||||
relation="res.partner",
|
||||
string="Partner",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'name': fields.related(
|
||||
'invoice_id', 'name',
|
||||
type="char",
|
||||
size=64,
|
||||
string="Description",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'number': fields.related(
|
||||
'invoice_id', 'number',
|
||||
type="char",
|
||||
size=64,
|
||||
string="Number",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'journal_id': fields.related(
|
||||
'invoice_id', 'journal_id',
|
||||
type="many2one",
|
||||
relation="account.journal",
|
||||
string="Journal",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'period_id': fields.related(
|
||||
'invoice_id', 'period_id',
|
||||
type="many2one",
|
||||
relation="account.period",
|
||||
string="Period",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'company_id': fields.related(
|
||||
'invoice_id', 'company_id',
|
||||
type="many2one",
|
||||
relation="res.company",
|
||||
string="Company",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'currency_id': fields.related(
|
||||
'invoice_id', 'currency_id',
|
||||
type="many2one",
|
||||
relation="res.currency",
|
||||
string="Currency",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'residual': fields.related(
|
||||
'invoice_id', 'residual',
|
||||
type="float",
|
||||
string="Residual",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'amount_total': fields.related(
|
||||
'invoice_id', 'amount_total',
|
||||
type="float",
|
||||
string="Total",
|
||||
store=True,
|
||||
readonly=True),
|
||||
'state':fields.related(
|
||||
'invoice_id','state',
|
||||
type='selection',
|
||||
selection=[
|
||||
('draft','Draft'),
|
||||
('proforma','Pro-forma'),
|
||||
('proforma2','Pro-forma'),
|
||||
('open','Open'),
|
||||
('paid','Paid'),
|
||||
('cancel','Cancelled'),
|
||||
],
|
||||
string='State',
|
||||
readonly=True,
|
||||
store=True),
|
||||
}
|
||||
|
||||
AccountHoursBlock()
|
||||
|
||||
|
||||
class AccountInvoice(osv.osv):
|
||||
############################################################################
|
||||
## Add hours blocks on invoice
|
||||
############################################################################
|
||||
class AccountInvoice(orm.Model):
|
||||
_inherit = 'account.invoice'
|
||||
_columns = {
|
||||
'account_hours_block_ids': fields.one2many('account.hours.block', 'invoice_id', 'Hours Block')
|
||||
}
|
||||
|
||||
AccountInvoice()
|
||||
_columns = {
|
||||
'account_hours_block_ids': fields.one2many(
|
||||
'account.hours.block',
|
||||
'invoice_id',
|
||||
string='Hours Block')
|
||||
}
|
||||
|
||||
@@ -20,31 +20,26 @@
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
from report import report_sxw
|
||||
from openerp.report import report_sxw
|
||||
|
||||
|
||||
class account_hours_block(report_sxw.rml_parse):
|
||||
def __init__(self, cr, uid, name, context=None):
|
||||
super(account_hours_block, self).__init__(cr, uid, name, context)
|
||||
super(account_hours_block, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
'format_date': self._get_and_change_date_format_for_swiss,
|
||||
'analytic_lines': self._get_analytic_lines,
|
||||
})
|
||||
self.context = context
|
||||
|
||||
def _get_analytic_lines(self, hours_block):
|
||||
al_pool = self.pool.get('account.analytic.line')
|
||||
al_ids = al_pool.search(self.cr, self.uid,
|
||||
[['invoice_id', '=', hours_block.invoice_id.id]],
|
||||
order='date desc')
|
||||
res = al_pool.browse(self.cr, self.uid, al_ids)
|
||||
return res
|
||||
|
||||
def _get_and_change_date_format_for_swiss(self, date_to_format):
|
||||
date_formatted = ''
|
||||
if date_to_format:
|
||||
date_formatted = strptime(date_to_format, '%Y-%m-%d').strftime('%d.%m.%Y')
|
||||
return date_formatted
|
||||
al_ids = al_pool.search(
|
||||
self.cr,
|
||||
self.uid,
|
||||
[('invoice_id', '=', hours_block.invoice_id.id)],
|
||||
order='date desc',
|
||||
context=self.context)
|
||||
return al_pool.browse(self.cr, self.uid, al_ids, context=self.context)
|
||||
|
||||
report_sxw.report_sxw('report.account.hours.block', 'account.hours.block', 'addons/analytic_hours_block/report/hours_block.rml', parser=account_hours_block)
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
<para style="P12a">Invoice Date : </para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="P2">[[ o.date_invoice and format_date(o.date_invoice) or '' ]]</para>
|
||||
<para style="P2">[[ o.date_invoice and formatLang(o.date_invoice, date=True) or '' ]]</para>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -243,7 +243,7 @@
|
||||
<tr>
|
||||
[[ repeatIn(analytic_lines(o),'l') ]]
|
||||
<td>
|
||||
<para style="P2">[[ l.date and format_date(l.date) or '' ]]</para>
|
||||
<para style="P2">[[ l.date and formatLang(l.date, date=True) or '' ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="P2">[[ l.name or '' ]]</para>
|
||||
|
||||
Reference in New Issue
Block a user