[DEL] hr_timesheet_invoice: deprecated module
Reason: complete rewrite of the Sale module. Invoicing is now managed through Sale. Responsible: fp, dbo, nim
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import hr_timesheet_invoice
|
||||
import wizard
|
||||
import report
|
||||
@@ -1,41 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
{
|
||||
'name': 'Invoice on Timesheets',
|
||||
'version': '1.0',
|
||||
'category': 'Sales Management',
|
||||
'description': """
|
||||
Generate your Invoices from Expenses, Timesheet Entries.
|
||||
========================================================
|
||||
|
||||
Module to generate invoices based on costs (human resources, expenses, ...).
|
||||
|
||||
You can define price lists in analytic account, make some theoretical revenue
|
||||
reports.""",
|
||||
'website': 'https://www.odoo.com/page/employees',
|
||||
'images': ['images/hr_bill_task_work.jpeg','images/hr_type_of_invoicing.jpeg'],
|
||||
'depends': ['hr_timesheet', 'report'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'hr_timesheet_invoice_data.xml',
|
||||
'hr_timesheet_invoice_view.xml',
|
||||
'hr_timesheet_invoice_wizard.xml',
|
||||
'hr_timesheet_invoice_report.xml',
|
||||
'report/report_analytic_view.xml',
|
||||
'report/hr_timesheet_invoice_report_view.xml',
|
||||
'wizard/hr_timesheet_analytic_profit_view.xml',
|
||||
'wizard/hr_timesheet_invoice_create_view.xml',
|
||||
'wizard/hr_timesheet_invoice_create_final_view.xml',
|
||||
'views/report_analyticprofit.xml',
|
||||
],
|
||||
'demo': ['hr_timesheet_invoice_demo.xml'],
|
||||
'test': ['../account/test/account_minimal_test.xml',
|
||||
'test/test_hr_timesheet_invoice.yml',
|
||||
'test/test_hr_timesheet_invoice_no_prod_tax.yml',
|
||||
'test/hr_timesheet_invoice_report.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
@@ -1,346 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
class hr_timesheet_invoice_factor(osv.osv):
|
||||
_name = "hr_timesheet_invoice.factor"
|
||||
_description = "Invoice Rate"
|
||||
_order = 'factor'
|
||||
_columns = {
|
||||
'name': fields.char('Internal Name', required=True, translate=True),
|
||||
'customer_name': fields.char('Name', help="Label for the customer"),
|
||||
'factor': fields.float('Discount (%)', required=True, help="Discount in percentage"),
|
||||
}
|
||||
_defaults = {
|
||||
'factor': lambda *a: 0.0,
|
||||
}
|
||||
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
_inherit = "account.analytic.account"
|
||||
_columns = {
|
||||
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist',
|
||||
help="The product to invoice is defined on the employee form, the price will be deducted by this pricelist on the product."),
|
||||
'amount_max': fields.float('Max. Invoice Price',
|
||||
help="Keep empty if this contract is not limited to a total fixed price."),
|
||||
'to_invoice': fields.many2one('hr_timesheet_invoice.factor', 'Timesheet Invoicing Ratio',
|
||||
help="You usually invoice 100% of the timesheets. But if you mix fixed price and timesheet invoicing, you may use another ratio. For instance, if you do a 20% advance invoice (fixed price, based on a sales order), you should invoice the rest on timesheet with a 80% ratio."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'pricelist_id': lambda self, cr, uid, c: self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'product.list0'),
|
||||
'to_invoice': lambda self, cr, uid, c: self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'hr_timesheet_invoice.timesheet_invoice_factor1')
|
||||
}
|
||||
|
||||
def on_change_partner_id(self, cr, uid, ids, partner_id, name, context=None):
|
||||
res = super(account_analytic_account, self).on_change_partner_id(cr, uid, ids, partner_id, name, context=context)
|
||||
if partner_id:
|
||||
part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
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):
|
||||
return self.write(cr, uid, ids, {'state': 'close'}, context=context)
|
||||
|
||||
def set_cancel(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'cancelled'}, context=context)
|
||||
|
||||
def set_open(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'open'}, context=context)
|
||||
|
||||
def set_pending(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'state': 'pending'}, context=context)
|
||||
|
||||
|
||||
class account_analytic_line(osv.osv):
|
||||
_inherit = 'account.analytic.line'
|
||||
_columns = {
|
||||
'invoice_id': fields.many2one('account.invoice', 'Invoice', ondelete="set null", copy=False),
|
||||
'to_invoice': fields.many2one('hr_timesheet_invoice.factor', 'Invoiceable', help="It allows to set the discount while making invoice, keep empty if the activities should not be invoiced."),
|
||||
}
|
||||
|
||||
def _default_general_account(self, cr, uid, context=None):
|
||||
proxy = self.pool.get('hr.employee')
|
||||
record_ids = proxy.search(cr, uid, [('user_id', '=', uid)], context=context)
|
||||
if record_ids:
|
||||
employee = proxy.browse(cr, uid, record_ids[0], context=context)
|
||||
if employee.product_id and employee.product_id.property_account_income_id:
|
||||
return employee.product_id.property_account_income_id.id
|
||||
return False
|
||||
|
||||
_defaults = {
|
||||
'general_account_id': _default_general_account,
|
||||
}
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
self._check_inv(cr, uid, ids, vals)
|
||||
return super(account_analytic_line, self).write(cr, uid, ids, vals,
|
||||
context=context)
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
if any(line.invoice_id.id for line in self.browse(cr, uid, ids, context)):
|
||||
raise UserError(_('You cannot delete an invoiced analytic line!'))
|
||||
return super(account_analytic_line, self).unlink(cr, uid, ids, context)
|
||||
|
||||
def _check_inv(self, cr, uid, ids, vals, context=None):
|
||||
select = ids
|
||||
if isinstance(select, (int, long)):
|
||||
select = [ids]
|
||||
if (not vals.has_key('invoice_id')) or vals['invoice_id'] == False:
|
||||
for line in self.browse(cr, uid, select, context):
|
||||
if line.invoice_id:
|
||||
raise UserError(_('You cannot modify an invoiced analytic line!'))
|
||||
return True
|
||||
|
||||
def _get_invoice_price(self, cr, uid, account, product_id, user_id, qty, context={}):
|
||||
pro_price_obj = self.pool.get('product.pricelist')
|
||||
if account.pricelist_id:
|
||||
pl = account.pricelist_id.id
|
||||
price = pro_price_obj.price_get(cr, uid, [pl], product_id, qty or 1.0, account.partner_id.id, context=context)[pl]
|
||||
else:
|
||||
price = 0.0
|
||||
return price
|
||||
|
||||
def _prepare_cost_invoice(self, cr, uid, partner, company_id, currency_id, analytic_line_ids, group_by_partner=False, context=None):
|
||||
""" returns values used to create main invoice from analytic lines"""
|
||||
account_payment_term_obj = self.pool['account.payment.term']
|
||||
if group_by_partner:
|
||||
invoice_name = partner.name
|
||||
else:
|
||||
invoice_name = analytic_line_ids[0].account_id.name
|
||||
date_due = False
|
||||
if partner.property_payment_term_id:
|
||||
pterm_list = account_payment_term_obj.compute(cr, uid,
|
||||
partner.property_payment_term_id.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][0]
|
||||
return {
|
||||
'name': "%s - %s" % (time.strftime('%d/%m/%Y'), invoice_name),
|
||||
'partner_id': partner.id,
|
||||
'company_id': company_id,
|
||||
'payment_term_id': partner.property_payment_term_id.id or False,
|
||||
'account_id': partner.property_account_receivable_id.id,
|
||||
'currency_id': currency_id,
|
||||
'date_due': date_due,
|
||||
'fiscal_position_id': partner.property_account_position_id.id
|
||||
}
|
||||
|
||||
def _prepare_cost_invoice_line(self, cr, uid, invoice_id, product_id, uom, user_id,
|
||||
factor_id, account, analytic_line_ids, journal_type, data, context=None):
|
||||
product_obj = self.pool['product.product']
|
||||
|
||||
uom_context = dict(context or {}, uom=uom)
|
||||
|
||||
total_price = sum(l.amount for l in analytic_line_ids)
|
||||
total_qty = sum(l.unit_amount for l in analytic_line_ids)
|
||||
|
||||
if data.get('product'):
|
||||
# force product, use its public price
|
||||
if isinstance(data['product'], (tuple, list)):
|
||||
product_id = data['product'][0]
|
||||
else:
|
||||
product_id = data['product']
|
||||
unit_price = self._get_invoice_price(cr, uid, account, product_id, user_id, total_qty, uom_context)
|
||||
elif journal_type == 'general' and product_id:
|
||||
# timesheets, use sale price
|
||||
unit_price = self._get_invoice_price(cr, uid, account, product_id, user_id, total_qty, uom_context)
|
||||
else:
|
||||
# expenses, using price from amount field
|
||||
unit_price = total_price*-1.0 / total_qty
|
||||
|
||||
factor = self.pool['hr_timesheet_invoice.factor'].browse(cr, uid, factor_id, context=uom_context)
|
||||
factor_name = factor.customer_name or ''
|
||||
curr_invoice_line = {
|
||||
'price_unit': unit_price,
|
||||
'quantity': total_qty,
|
||||
'product_id': product_id,
|
||||
'discount': factor.factor,
|
||||
'invoice_id': invoice_id,
|
||||
'name': factor_name,
|
||||
'uos_id': uom,
|
||||
'account_analytic_id': account.id,
|
||||
}
|
||||
|
||||
if product_id:
|
||||
product = product_obj.browse(cr, uid, product_id, context=uom_context)
|
||||
factor_name = product_obj.name_get(cr, uid, [product_id], context=uom_context)[0][1]
|
||||
if factor.customer_name:
|
||||
factor_name += ' - ' + factor.customer_name
|
||||
|
||||
general_account = product.property_account_income_id or product.categ_id.property_account_income_categ_id
|
||||
if not general_account:
|
||||
raise UserError(_("Configuration Error!") + '\n' + _("Please define income account for product '%s'.") % product.name)
|
||||
taxes = product.taxes_id or general_account.tax_ids
|
||||
tax = self.pool['account.fiscal.position'].map_tax(cr, uid, account.partner_id.property_account_position_id, taxes)
|
||||
curr_invoice_line.update({
|
||||
'invoice_line_tax_ids': [(6, 0, tax)],
|
||||
'name': factor_name,
|
||||
'account_id': general_account.id,
|
||||
})
|
||||
|
||||
note = []
|
||||
for line in analytic_line_ids:
|
||||
# set invoice_line_note
|
||||
details = []
|
||||
if data.get('date', False):
|
||||
details.append(line['date'])
|
||||
if data.get('time', False):
|
||||
if line['product_uom_id']:
|
||||
details.append("%s %s" % (line.unit_amount, line.product_uom_id.name))
|
||||
else:
|
||||
details.append("%s" % (line['unit_amount'], ))
|
||||
if data.get('name', False):
|
||||
details.append(line['name'])
|
||||
if details:
|
||||
note.append(u' - '.join(map(lambda x: unicode(x) or '', details)))
|
||||
if note:
|
||||
curr_invoice_line['name'] += "\n" + ("\n".join(map(lambda x: unicode(x) or '', note)))
|
||||
return curr_invoice_line
|
||||
|
||||
def invoice_cost_create(self, cr, uid, ids, data=None, context=None):
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||
analytic_line_obj = self.pool.get('account.analytic.line')
|
||||
invoices = []
|
||||
if context is None:
|
||||
context = {}
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
# use key (partner/account, company, currency)
|
||||
# creates one invoice per key
|
||||
invoice_grouping = {}
|
||||
# grouping on partner instead of analytic account
|
||||
group_by_partner = data.get('group_by_partner', False)
|
||||
|
||||
currency_id = False
|
||||
# prepare for iteration on journal and accounts
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
# check if currency is the same in different accounts when grouping by partner
|
||||
if not currency_id :
|
||||
|
||||
currency_id = line.account_id.pricelist_id.currency_id.id
|
||||
if line.account_id.pricelist_id and line.account_id.pricelist_id.currency_id:
|
||||
if line.account_id.pricelist_id.currency_id.id != currency_id and group_by_partner:
|
||||
raise UserError(_('You cannot group invoices having different currencies on different analytic accounts for the same partner.'))
|
||||
|
||||
if group_by_partner:
|
||||
key = (line.account_id.partner_id.id,
|
||||
line.account_id.company_id.id,
|
||||
line.account_id.pricelist_id.currency_id.id)
|
||||
invoice_grouping.setdefault(key, []).append(line)
|
||||
else:
|
||||
key = (line.account_id.id,
|
||||
line.account_id.company_id.id,
|
||||
line.account_id.pricelist_id.currency_id.id)
|
||||
invoice_grouping.setdefault(key, []).append(line)
|
||||
|
||||
for (key_id, company_id, currency_id), analytic_line_ids in invoice_grouping.items():
|
||||
# key_id is either an account.analytic.account, either a res.partner
|
||||
# don't really care, what's important is the analytic lines that
|
||||
# will be used to create the invoice lines
|
||||
account = analytic_line_ids[0].account_id
|
||||
partner = account.partner_id # will be the same for every line
|
||||
if (not partner) or not (currency_id):
|
||||
raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
|
||||
|
||||
curr_invoice = self._prepare_cost_invoice(cr, uid, partner, company_id, currency_id, analytic_line_ids, group_by_partner, context=context)
|
||||
invoice_context = dict(context,
|
||||
lang=partner.lang,
|
||||
force_company=company_id, # set force_company in context so the correct product properties are selected (eg. income account)
|
||||
company_id=company_id) # set company_id in context, so the correct default journal will be selected
|
||||
last_invoice = invoice_obj.create(cr, uid, curr_invoice, context=invoice_context)
|
||||
invoices.append(last_invoice)
|
||||
|
||||
# use key (product, uom, user, invoiceable, analytic account, journal type)
|
||||
# creates one invoice line per key
|
||||
invoice_lines_grouping = {}
|
||||
for analytic_line in analytic_line_ids:
|
||||
account = analytic_line.account_id
|
||||
|
||||
if not analytic_line.to_invoice:
|
||||
raise UserError(_('Trying to invoice non invoiceable line for %s.') % (analytic_line.product_id.name))
|
||||
|
||||
if not analytic_line.product_id and not data['product']:
|
||||
raise UserError(_('No product associated with %s, force a product.') % (analytic_line.name))
|
||||
|
||||
key = (analytic_line.product_id.id,
|
||||
analytic_line.product_uom_id.id,
|
||||
analytic_line.user_id.id,
|
||||
analytic_line.to_invoice.id,
|
||||
analytic_line.account_id,
|
||||
analytic_line.journal_id.type)
|
||||
# We want to retrieve the data in the partner language for the invoice creation
|
||||
analytic_line = analytic_line_obj.browse(cr, uid , [line.id for line in analytic_line], context=invoice_context)
|
||||
invoice_lines_grouping.setdefault(key, []).append(analytic_line)
|
||||
|
||||
# finally creates the invoice line
|
||||
for (product_id, uom, user_id, factor_id, account, journal_type), lines_to_invoice in invoice_lines_grouping.items():
|
||||
curr_invoice_line = self._prepare_cost_invoice_line(cr, uid, last_invoice,
|
||||
product_id, uom, user_id, factor_id, account, lines_to_invoice,
|
||||
journal_type, data, context=invoice_context)
|
||||
|
||||
invoice_line_obj.create(cr, uid, curr_invoice_line, context=context)
|
||||
self.write(cr, uid, [l.id for l in analytic_line_ids], {'invoice_id': last_invoice}, context=context)
|
||||
invoice_obj.compute_taxes(cr, uid, [last_invoice], context)
|
||||
return invoices
|
||||
|
||||
def on_change_account_id(self, cr, uid, ids, account_id, user_id=False, unit_amount=0, is_timesheet=False, context=None):
|
||||
res = {'value': {}}
|
||||
if is_timesheet and account_id:
|
||||
acc = self.pool.get('account.analytic.account').browse(cr, uid, account_id, context=context)
|
||||
st = acc.to_invoice.id
|
||||
res['value']['to_invoice'] = st or False
|
||||
if acc.state == 'pending':
|
||||
res['warning'] = {
|
||||
'title': _('Warning'),
|
||||
'message': _('The analytic account is in pending state.\nYou should not work on this account !')
|
||||
}
|
||||
elif acc.state == 'close' or acc.state == 'cancelled':
|
||||
raise osv.except_osv(_('Invalid Analytic Account!'), _('You cannot select a Analytic Account which is in Close or Cancelled state.'))
|
||||
return res
|
||||
|
||||
|
||||
class account_invoice(osv.osv):
|
||||
_inherit = "account.invoice"
|
||||
|
||||
def _get_analytic_lines(self, cr, uid, ids, context=None):
|
||||
iml = super(account_invoice, self)._get_analytic_lines(cr, uid, ids, context=context)
|
||||
|
||||
inv = self.browse(cr, uid, ids, context=context)[0]
|
||||
if inv.type == 'in_invoice':
|
||||
obj_analytic_account = self.pool.get('account.analytic.account')
|
||||
for il in iml:
|
||||
if il['account_analytic_id']:
|
||||
# *-* browse (or refactor to avoid read inside the loop)
|
||||
to_invoice = obj_analytic_account.read(cr, uid, [il['account_analytic_id']], ['to_invoice'], context=context)[0]['to_invoice']
|
||||
if to_invoice:
|
||||
il['analytic_line_ids'][0][2]['to_invoice'] = to_invoice[0]
|
||||
return iml
|
||||
|
||||
|
||||
class account_move_line(osv.osv):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def create_analytic_lines(self, cr, uid, ids, context=None):
|
||||
res = super(account_move_line, self).create_analytic_lines(cr, uid, ids, context=context)
|
||||
analytic_line_obj = self.pool.get('account.analytic.line')
|
||||
for move_line in self.browse(cr, uid, ids, context=context):
|
||||
# For customer invoice, link analytic line to the invoice so it is not proposed for invoicing in Bill Tasks Work
|
||||
invoice_id = move_line.invoice_id and move_line.invoice_id.type in ('out_invoice', 'out_refund') and move_line.invoice_id.id or False
|
||||
for line in move_line.analytic_line_ids:
|
||||
analytic_line_obj.write(cr, uid, line.id, {
|
||||
'invoice_id': invoice_id,
|
||||
'to_invoice': line.account_id.to_invoice and line.account_id.to_invoice.id or False
|
||||
}, context=context)
|
||||
return res
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="timesheet_invoice_factor1" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">Yes (100%)</field>
|
||||
<field name="customer_name">100%</field>
|
||||
<field name="factor">0.0</field>
|
||||
</record>
|
||||
<record id="timesheet_invoice_factor2" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">90%</field>
|
||||
<field name="customer_name">90%</field>
|
||||
<field name="factor">10.0</field>
|
||||
</record>
|
||||
<record id="timesheet_invoice_factor3" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">50%</field>
|
||||
<field name="customer_name">50%</field>
|
||||
<field name="factor">50.0</field>
|
||||
</record>
|
||||
<record id="timesheet_invoice_factor4" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">80%</field>
|
||||
<field name="customer_name">80%</field>
|
||||
<field name="factor">20.0</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="timesheet_invoice_factor2" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">50%</field>
|
||||
<field name="customer_name">50% Discount</field>
|
||||
<field name="factor">50.0</field>
|
||||
</record>
|
||||
<record id="timesheet_invoice_factor3" model="hr_timesheet_invoice.factor">
|
||||
<field name="name">Free of charge</field>
|
||||
<field name="customer_name">Offered developments</field>
|
||||
<field name="factor">100.0</field>
|
||||
</record>
|
||||
<record id="analytic.analytic_spark" model="account.analytic.account">
|
||||
<field name="to_invoice" ref="timesheet_invoice_factor1"/>
|
||||
</record>
|
||||
<record id="analytic.analytic_nebula" model="account.analytic.account">
|
||||
<field name="to_invoice" ref="timesheet_invoice_factor1"/>
|
||||
</record>
|
||||
<record id="analytic.analytic_partners_camp_to_camp" model="account.analytic.account">
|
||||
<field name="to_invoice" ref="timesheet_invoice_factor1"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<report
|
||||
id="action_report_analytic_profit"
|
||||
model="account.analytic.line"
|
||||
name="hr_timesheet_invoice.report_analyticprofit"
|
||||
file="hr_timesheet_invoice.report_analyticprofit"
|
||||
report_type="qweb-pdf"
|
||||
menu="False"
|
||||
string="Timesheet Profit"
|
||||
/>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,134 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="account_analytic_account_form_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.account.invoice.form</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
<field name="priority">30</field>
|
||||
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="/form/sheet" position='before'>
|
||||
<header attrs="{'invisible': [('type','=','template')]}">
|
||||
<button name="set_pending" string="To Renew" type="object" states="open" />
|
||||
<button name="set_close" string="Close Contract" type="object" states="open,pending" />
|
||||
<button name="set_open" string="Set In Progress" type="object" states="pending,close,cancelled,draft" />
|
||||
<button name="set_cancel" string="Cancel Contract" type="object" states="open,pending"/>
|
||||
<field name="state" readonly="1" widget="statusbar"
|
||||
statusbar_visible="open,pending,close" statusbar_colors='{"pending":"red", "template":"blue"}'/>
|
||||
</header>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_timesheet_line_form" model="ir.ui.view">
|
||||
<field name="name">account.analytic.line.form</field>
|
||||
<field name="model">account.analytic.line</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='accounting']" position='after'>
|
||||
<group string="Invoicing">
|
||||
<field name="to_invoice"/>
|
||||
<field name="invoice_id" readonly="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<field name="account_id" position="attributes">
|
||||
<attribute name="domain">[('type','in',['normal','contract']),('state', '!=', 'close'),('invoice_on_timesheets','=',1)]</attribute>
|
||||
<attribute name="on_change">on_change_account_id(account_id, user_id, unit_amount, is_timesheet, context)</attribute>
|
||||
<attribute name="context">{'default_invoice_on_timesheets': 1}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_timesheet_line_tree" model="ir.ui.view">
|
||||
<field name="name">account.analytic.line.tree</field>
|
||||
<field name="model">account.analytic.line</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="amount" position="after">
|
||||
<field name="to_invoice"/>
|
||||
<field name="invoice_id" readonly="1"/>
|
||||
</field>
|
||||
<field name="account_id" position="attributes">
|
||||
<attribute name="domain">[('type','in',['normal','contract']),('state', '!=', 'close'),('invoice_on_timesheets','=',1)]</attribute>
|
||||
<attribute name="on_change">on_change_account_id(account_id, user_id, unit_amount, is_timesheet, context)</attribute>
|
||||
<attribute name="context">{'default_invoice_on_timesheets': 1}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_line_view_search_to_invoice" model="ir.ui.view">
|
||||
<field name="name">account.analytic.line.search.to_invoice</field>
|
||||
<field name="model">account.analytic.line</field>
|
||||
<field name="inherit_id" ref="hr_timesheet.hr_timesheet_line_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='account_id']" position="after">
|
||||
<separator/>
|
||||
<filter name="to_invoice" string="To Invoice" context="{'to_invoice': 1}" domain="[('invoice_id','=',False), ('to_invoice','!=',False)]"/>
|
||||
<filter name="invoiced" string="Invoiced" domain="[('invoice_id','!=',False), ('to_invoice','!=',False)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_timesheet_invoice_factor_search" model="ir.ui.view">
|
||||
<field name="name">hr_timesheet_invoice.factor.search</field>
|
||||
<field name="model">hr_timesheet_invoice.factor</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Type of invoicing">
|
||||
<field name="name" string="Type of invoicing"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_hr_timesheet_invoice_factor_form" model="ir.ui.view">
|
||||
<field name="name">hr_timesheet_invoice.factor.form</field>
|
||||
<field name="model">hr_timesheet_invoice.factor</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Type of invoicing">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="customer_name"/>
|
||||
<field name="factor"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_hr_timesheet_invoice_factor_tree" model="ir.ui.view">
|
||||
<field name="name">hr_timesheet_invoice.factor.tree</field>
|
||||
<field name="model">hr_timesheet_invoice.factor</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Types of invoicing">
|
||||
<field name="name"/>
|
||||
<field name="customer_name"/>
|
||||
<field name="factor"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_hr_timesheet_invoice_factor_form" model="ir.actions.act_window">
|
||||
<field name="name">Invoicing Types</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="context">{"default_is_timesheet":1}</field>
|
||||
<field name="res_model">hr_timesheet_invoice.factor</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_hr_timesheet_invoice_factor_tree"/>
|
||||
<field name="search_view_id" ref="view_hr_timesheet_invoice_factor_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to add a new type of invoicing.
|
||||
</p><p>
|
||||
Odoo allows you to create default invoicing types. You might
|
||||
have to regularly assign discounts because of a specific
|
||||
contract or agreement with a customer. From this menu, you can
|
||||
create additional types of invoicing to speed up your
|
||||
invoicing.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem
|
||||
action="action_hr_timesheet_invoice_factor_form"
|
||||
id="hr_timesheet_invoice_factor_view"
|
||||
parent="account.menu_analytic_accounting" sequence="99" groups="base.group_no_one"/>
|
||||
|
||||
<record id="hr_timesheet.act_hr_timesheet_accounts_form" model="ir.actions.act_window">
|
||||
<field name="context">{'invoice_on_timesheets':1, 'default_type': 'contract'}</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import account_analytic_profit
|
||||
import report_analytic
|
||||
import hr_timesheet_invoice_report
|
||||
@@ -1,111 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.report import report_sxw
|
||||
from openerp.osv import osv
|
||||
|
||||
|
||||
class account_analytic_profit(report_sxw.rml_parse):
|
||||
def __init__(self, cr, uid, name, context):
|
||||
super(account_analytic_profit, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'lines': self._lines,
|
||||
'user_ids': self._user_ids,
|
||||
'journal_ids': self._journal_ids,
|
||||
'line': self._line,
|
||||
})
|
||||
|
||||
def _user_ids(self, lines):
|
||||
user_obj = self.pool['res.users']
|
||||
ids=list(set([b.user_id.id for b in lines]))
|
||||
return user_obj.browse(self.cr, self.uid, ids)
|
||||
|
||||
def _journal_ids(self, form, user_id):
|
||||
if isinstance(user_id, (int, long)):
|
||||
user_id = [user_id]
|
||||
line_obj = self.pool['account.analytic.line']
|
||||
journal_obj = self.pool['account.analytic.journal']
|
||||
line_ids=line_obj.search(self.cr, self.uid, [
|
||||
('date', '>=', form['date_from']),
|
||||
('date', '<=', form['date_to']),
|
||||
('journal_id', 'in', form['journal_ids'][0][2]),
|
||||
('user_id', 'in', user_id),
|
||||
])
|
||||
ids=list(set([b.journal_id.id for b in line_obj.browse(self.cr, self.uid, line_ids)]))
|
||||
return journal_obj.browse(self.cr, self.uid, ids)
|
||||
|
||||
def _line(self, form, journal_ids, user_ids):
|
||||
line_obj = self.pool['account.analytic.line']
|
||||
product_obj = self.pool['product.product']
|
||||
price_obj = self.pool['product.pricelist']
|
||||
ids=line_obj.search(self.cr, self.uid, [
|
||||
('date', '>=', form['date_from']),
|
||||
('date', '<=', form['date_to']),
|
||||
('journal_id', 'in', journal_ids),
|
||||
('user_id', 'in', user_ids),
|
||||
])
|
||||
res={}
|
||||
for line in line_obj.browse(self.cr, self.uid, ids):
|
||||
if line.account_id.pricelist_id:
|
||||
if line.account_id.to_invoice:
|
||||
if line.to_invoice:
|
||||
id=line.to_invoice.id
|
||||
name=line.to_invoice.name
|
||||
discount=line.to_invoice.factor
|
||||
else:
|
||||
name="/"
|
||||
discount=1.0
|
||||
id = -1
|
||||
else:
|
||||
name="Fixed"
|
||||
discount=0.0
|
||||
id=0
|
||||
pl=line.account_id.pricelist_id.id
|
||||
price=price_obj.price_get(self.cr, self.uid, [pl], line.product_id.id, line.unit_amount or 1.0, line.account_id.partner_id.id)[pl]
|
||||
else:
|
||||
name="/"
|
||||
discount=1.0
|
||||
id = -1
|
||||
price=0.0
|
||||
if id not in res:
|
||||
res[id]={'name': name, 'amount': 0, 'cost':0, 'unit_amount':0,'amount_th':0}
|
||||
xxx = round(price * line.unit_amount * (1-(discount or 0.0)), 2)
|
||||
res[id]['amount_th']+=xxx
|
||||
if line.invoice_id:
|
||||
self.cr.execute('select id from account_analytic_line where invoice_id=%s', (line.invoice_id.id,))
|
||||
tot = 0
|
||||
for lid in self.cr.fetchall():
|
||||
lid2 = line_obj.browse(self.cr, self.uid, lid[0])
|
||||
pl=lid2.account_id.pricelist_id.id
|
||||
price=price_obj.price_get(self.cr, self.uid, [pl], lid2.product_id.id, lid2.unit_amount or 1.0, lid2.account_id.partner_id.id)[pl]
|
||||
tot += price * lid2.unit_amount * (1-(discount or 0.0))
|
||||
if tot:
|
||||
percent = line.invoice_id.amount_untaxed / tot
|
||||
res[id]['amount'] += xxx * percent
|
||||
else:
|
||||
res[id]['amount'] += xxx
|
||||
else:
|
||||
res[id]['amount'] += xxx
|
||||
res[id]['cost']+=line.amount
|
||||
res[id]['unit_amount']+=line.unit_amount
|
||||
for id in res:
|
||||
res[id]['profit']=res[id]['amount']+res[id]['cost']
|
||||
res[id]['eff']=res[id]['cost'] and '%d' % (-res[id]['amount'] / res[id]['cost'] * 100,) or 0.0
|
||||
return res.values()
|
||||
|
||||
def _lines(self, form):
|
||||
line_obj = self.pool['account.analytic.line']
|
||||
ids=line_obj.search(self.cr, self.uid, [
|
||||
('date', '>=', form['date_from']),
|
||||
('date', '<=', form['date_to']),
|
||||
('journal_id', 'in', form['journal_ids'][0][2]),
|
||||
('user_id', 'in', form['employee_ids'][0][2]),
|
||||
])
|
||||
return line_obj.browse(self.cr, self.uid, ids)
|
||||
|
||||
|
||||
class report_account_analytic_profit(osv.AbstractModel):
|
||||
_name = 'report.hr_timesheet_invoice.report_analyticprofit'
|
||||
_inherit = 'report.abstract_report'
|
||||
_template = 'hr_timesheet_invoice.report_analyticprofit'
|
||||
_wrapped_report_class = account_analytic_profit
|
||||
@@ -1,195 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.tools.sql import drop_view_if_exists
|
||||
|
||||
class report_timesheet_line(osv.osv):
|
||||
_name = "report.timesheet.line"
|
||||
_description = "Timesheet Line"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.char('Year', required=False, readonly=True),
|
||||
'user_id': fields.many2one('res.users', 'User', readonly=True),
|
||||
'date': fields.date('Date', readonly=True),
|
||||
'day': fields.char('Day', size=128, readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'cost': fields.float('Cost', readonly=True),
|
||||
'product_id': fields.many2one('product.product', 'Product',readonly=True),
|
||||
'account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
'general_account_id': fields.many2one('account.account', 'Financial Account', readonly=True, domain=[('deprecated', '=', False)]),
|
||||
'invoice_id': fields.many2one('account.invoice', 'Invoiced', 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),
|
||||
}
|
||||
_order = 'name desc,user_id desc'
|
||||
def init(self, cr):
|
||||
drop_view_if_exists(cr, 'report_timesheet_line')
|
||||
cr.execute("""
|
||||
create or replace view report_timesheet_line as (
|
||||
select
|
||||
min(l.id) as id,
|
||||
l.date as date,
|
||||
to_char(l.date,'YYYY') as name,
|
||||
to_char(l.date,'MM') as month,
|
||||
l.user_id,
|
||||
to_char(l.date, 'YYYY-MM-DD') as day,
|
||||
l.invoice_id,
|
||||
l.product_id,
|
||||
l.account_id,
|
||||
l.general_account_id,
|
||||
sum(l.unit_amount) as quantity,
|
||||
sum(l.amount) as cost
|
||||
from
|
||||
account_analytic_line l
|
||||
where
|
||||
l.user_id is not null
|
||||
group by
|
||||
l.date,
|
||||
l.user_id,
|
||||
l.product_id,
|
||||
l.account_id,
|
||||
l.general_account_id,
|
||||
l.invoice_id
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
|
||||
|
||||
class report_timesheet_user(osv.osv):
|
||||
_name = "report_timesheet.user"
|
||||
_description = "Timesheet per day"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.char('Year', required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'cost': fields.float('Cost', 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),
|
||||
}
|
||||
_order = 'name desc,user_id desc'
|
||||
def init(self, cr):
|
||||
drop_view_if_exists(cr, 'report_timesheet_user')
|
||||
cr.execute("""
|
||||
create or replace view report_timesheet_user as (
|
||||
select
|
||||
min(l.id) as id,
|
||||
to_char(l.date,'YYYY') as name,
|
||||
to_char(l.date,'MM') as month,
|
||||
l.user_id,
|
||||
sum(l.unit_amount) as quantity,
|
||||
sum(l.amount) as cost
|
||||
from
|
||||
account_analytic_line l
|
||||
where
|
||||
user_id is not null
|
||||
group by l.date, to_char(l.date,'YYYY'),to_char(l.date,'MM'), l.user_id
|
||||
)
|
||||
""")
|
||||
|
||||
class report_timesheet_account(osv.osv):
|
||||
_name = "report_timesheet.account"
|
||||
_description = "Timesheet per account"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.char('Year', required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
'quantity': fields.float('Time', 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),
|
||||
|
||||
}
|
||||
_order = 'name desc,account_id desc,user_id desc'
|
||||
def init(self, cr):
|
||||
drop_view_if_exists(cr, 'report_timesheet_account')
|
||||
cr.execute("""
|
||||
create or replace view report_timesheet_account as (
|
||||
select
|
||||
min(id) as id,
|
||||
to_char(create_date, 'YYYY') as name,
|
||||
to_char(create_date,'MM') as month,
|
||||
user_id,
|
||||
account_id,
|
||||
sum(unit_amount) as quantity
|
||||
from
|
||||
account_analytic_line
|
||||
group by
|
||||
to_char(create_date, 'YYYY'),to_char(create_date, 'MM'), user_id, account_id
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
class report_timesheet_account_date(osv.osv):
|
||||
_name = "report_timesheet.account.date"
|
||||
_description = "Daily timesheet per account"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.char('Year', required=False, readonly=True),
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True),
|
||||
'quantity': fields.float('Time', 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),
|
||||
}
|
||||
_order = 'name desc,account_id desc,user_id desc'
|
||||
|
||||
def init(self, cr):
|
||||
drop_view_if_exists(cr, 'report_timesheet_account_date')
|
||||
cr.execute("""
|
||||
create or replace view report_timesheet_account_date as (
|
||||
select
|
||||
min(id) as id,
|
||||
to_char(date,'YYYY') as name,
|
||||
to_char(date,'MM') as month,
|
||||
user_id,
|
||||
account_id,
|
||||
sum(unit_amount) as quantity
|
||||
from
|
||||
account_analytic_line
|
||||
group by
|
||||
to_char(date,'YYYY'),to_char(date,'MM'), user_id, account_id
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
class report_timesheet_invoice(osv.osv):
|
||||
_name = "report_timesheet.invoice"
|
||||
_description = "Costs to invoice"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'user_id':fields.many2one('res.users', 'User', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Project', readonly=True),
|
||||
'manager_id':fields.many2one('res.users', 'Manager', readonly=True),
|
||||
'quantity': fields.float('Time', readonly=True),
|
||||
'amount_invoice': fields.float('To invoice', readonly=True)
|
||||
}
|
||||
_rec_name = 'user_id'
|
||||
_order = 'user_id desc'
|
||||
def init(self, cr):
|
||||
drop_view_if_exists(cr, 'report_timesheet_invoice')
|
||||
cr.execute("""
|
||||
create or replace view report_timesheet_invoice as (
|
||||
select
|
||||
min(l.id) as id,
|
||||
l.user_id as user_id,
|
||||
l.account_id as account_id,
|
||||
a.user_id as manager_id,
|
||||
sum(l.unit_amount) as quantity,
|
||||
sum(l.unit_amount * t.list_price) as amount_invoice
|
||||
from account_analytic_line l
|
||||
left join hr_timesheet_invoice_factor f on (l.to_invoice=f.id)
|
||||
left join account_analytic_account a on (l.account_id=a.id)
|
||||
left join product_product p on (l.to_invoice=f.id)
|
||||
left join product_template t on (l.to_invoice=f.id)
|
||||
where
|
||||
l.to_invoice is not null and
|
||||
l.invoice_id is null
|
||||
group by
|
||||
l.user_id,
|
||||
l.account_id,
|
||||
a.user_id
|
||||
)
|
||||
""")
|
||||
@@ -1,361 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_timesheet_line_graph" model="ir.ui.view">
|
||||
<field name="name">report.timesheet.line.graph</field>
|
||||
<field name="model">report.timesheet.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Timesheet Line" type="bar">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
<field group="True" name="user_id"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_line_tree" model="ir.ui.view">
|
||||
<field name="name">report.timesheet.line.tree</field>
|
||||
<field name="model">report.timesheet.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Timesheet Line">
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="day" invisible="1"/>
|
||||
<field name="quantity" sum="Quantity"/>
|
||||
<field name="cost" sum="Cost"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="month" invisible="1"/>
|
||||
<field name="account_id" invisible="1" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="invoice_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_line_search" model="ir.ui.view">
|
||||
<field name="name">report.timesheet.line.search</field>
|
||||
<field name="model">report.timesheet.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Timesheet by user">
|
||||
<filter string="Non Assigned timesheets to users" help="Non Assigned timesheets to users" domain="[('user_id','=',False)]"/>
|
||||
<field name="user_id"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="product_id"/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="date"/>
|
||||
<field name="invoice_id"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="User" name="User" context="{'group_by':'user_id'}"/>
|
||||
<filter string="Account" context="{'group_by':'account_id'}"/>
|
||||
<filter string="Product" context="{'group_by':'product_id'}"/>
|
||||
<filter string="Invoice" context="{'group_by':'invoice_id'}"/>
|
||||
<filter string="Day" context="{'group_by':'day'}"/>
|
||||
<filter string="Month" context="{'group_by':'month'}"/>
|
||||
<filter string="Year" context="{'group_by':'name'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_timesheet_line_stat_all" model="ir.actions.act_window">
|
||||
<field name="name">Timesheet Line</field>
|
||||
<field name="res_model">report.timesheet.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="context">{'search_default_month':1,'search_default_User':1,'search_default_user_id':uid,'group_by_no_leaf':1,'group_by':[]}</field>
|
||||
<field name="search_view_id" ref="view_timesheet_line_search"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Statistics report on timesheet by user -->
|
||||
|
||||
<record id="view_timesheet_user_graph" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.user.graph</field>
|
||||
<field name="model">report_timesheet.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Timesheet by user" type="bar">
|
||||
<field name="name"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
<field group="True" name="user_id"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_user_form" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.user.form</field>
|
||||
<field name="model">report_timesheet.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Timesheet by user">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="user_id"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_user_tree" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.user.tree</field>
|
||||
<field name="model">report_timesheet.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Timesheet by user">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="user_id"/>
|
||||
<field name="quantity"/>
|
||||
<field name="cost"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_account_date_graph_account" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.account.date.graph</field>
|
||||
<field name="model">report_timesheet.account.date</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph orientation="horizontal" string="Daily timesheet per account" type="bar">
|
||||
<field name="name"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
<field group="True" name="account_id"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_user_search" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.user.search</field>
|
||||
<field name="model">report_timesheet.user</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Timesheet by user">
|
||||
<field name="name" string="Timesheet by users"/>
|
||||
<field name="month"/>
|
||||
<field name="user_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_timesheet_user_stat_all" model="ir.actions.act_window">
|
||||
<field name="name">Timesheet by User</field>
|
||||
<field name="res_model">report_timesheet.user</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
<field name="context">{"search_default_user_id":uid}</field>
|
||||
<field name="search_view_id" ref="view_timesheet_user_search"/>
|
||||
</record>
|
||||
|
||||
<!-- Statistics report on timesheets to invoice -->
|
||||
|
||||
<record id="view_timesheet_invoice_graph" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.invoice.graph</field>
|
||||
<field name="model">report_timesheet.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Timesheet by invoice">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="amount_invoice" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_invoice_form" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.invoice.form</field>
|
||||
<field name="model">report_timesheet.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Timesheet by invoice">
|
||||
<group col="4">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="user_id"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_invoice_search" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.invoice.search</field>
|
||||
<field name="model">report_timesheet.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Timesheet by invoice">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="user_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_invoice_tree" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.invoice.tree</field>
|
||||
<field name="model">report_timesheet.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Timesheets to invoice">
|
||||
<field name="user_id"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="manager_id"/>
|
||||
<field name="quantity"/>
|
||||
<field name="amount_invoice"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_timesheet_invoice_stat_all" model="ir.actions.act_window">
|
||||
<field name="name">Timesheet by Invoice</field>
|
||||
<field name="res_model">report_timesheet.invoice</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
<field name="context">{"search_default_user_id":uid}</field>
|
||||
<field name="search_view_id" ref="view_timesheet_invoice_search"/>
|
||||
</record>
|
||||
|
||||
<!-- Statistics report on daily timesheets per account -->
|
||||
|
||||
<record id="view_timesheet_account_date_tree" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.account.date.tree</field>
|
||||
<field name="model">report_timesheet.account.date</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Daily timesheet per account">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
<field name="quantity"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_timesheet_account_date_graph" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.account.date.graph</field>
|
||||
<field name="model">report_timesheet.account.date</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Daily timesheet per account">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_account_date_form" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.account.date.form</field>
|
||||
<field name="model">report_timesheet.account.date</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Daily timesheet by account">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
<field name="quantity"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_account_date_search" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.account.date.search</field>
|
||||
<field name="model">report_timesheet.account.date</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Daily timesheet by account">
|
||||
<field name="name" string="Timesheet by account"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_timesheet_account_date_stat_all" model="ir.actions.act_window">
|
||||
<field name="name">Daily Timesheet by Account</field>
|
||||
<field name="res_model">report_timesheet.account.date</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
<field name="context">{"search_default_user_id":uid}</field>
|
||||
<field name="search_view_id" ref="view_timesheet_account_date_search"/>
|
||||
</record>
|
||||
|
||||
<!-- Statistics report on timesheets per account -->
|
||||
|
||||
<record id="view_timesheet_account_tree" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.account.tree</field>
|
||||
<field name="model">report_timesheet.account</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Timesheet per account">
|
||||
<field name="name"/>
|
||||
<field name="month" />
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
<field name="quantity"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_timesheet_account_graph" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.account.graph</field>
|
||||
<field name="model">report_timesheet.account</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Timesheet per account">
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_account_form" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.account.form</field>
|
||||
<field name="model">report_timesheet.account</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Timesheet by account">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
<field name="quantity"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_timesheet_account_search" model="ir.ui.view">
|
||||
<field name="name">report_timesheet.timesheet.account.search</field>
|
||||
<field name="model">report_timesheet.account</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Timesheet by account">
|
||||
<field name="name" string="Timesheet by account"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="user_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="action_timesheet_account_stat_all" model="ir.actions.act_window">
|
||||
<field name="name">Timesheet by Account</field>
|
||||
<field name="res_model">report_timesheet.account</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
<field name="search_view_id" ref="view_timesheet_account_search"/>
|
||||
</record>
|
||||
|
||||
<act_window
|
||||
context="{'search_default_user_id': [active_id]}"
|
||||
id="act_res_users_2_report_timesheet_user"
|
||||
name="Timesheets per day"
|
||||
res_model="report_timesheet.user"
|
||||
src_model="res.users"/>
|
||||
|
||||
|
||||
<act_window
|
||||
context="{'search_default_user_id': [active_id]}"
|
||||
id="act_res_users_2_report_timehsheet_account"
|
||||
name="Timesheets per account"
|
||||
res_model="report_timesheet.account"
|
||||
src_model="res.users"/>
|
||||
|
||||
<act_window
|
||||
context="{'search_default_manager_id': [active_id]}"
|
||||
id="act_res_users_2_report_timesheet_invoice"
|
||||
name="Costs to invoice"
|
||||
res_model="report_timesheet.invoice"
|
||||
src_model="res.users"/>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,88 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp import tools
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
|
||||
|
||||
class report_analytic_account_close(osv.osv):
|
||||
_name = "report.analytic.account.close"
|
||||
_description = "Analytic account to close"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
|
||||
'state': fields.char('Status', readonly=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner', readonly=True),
|
||||
'quantity': fields.float('Quantity', readonly=True),
|
||||
'quantity_max': fields.float('Max. Quantity', readonly=True),
|
||||
'balance': fields.float('Balance', readonly=True),
|
||||
'date_deadline': fields.date('Deadline', readonly=True),
|
||||
}
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_analytic_account_close')
|
||||
cr.execute("""
|
||||
create or replace view report_analytic_account_close as (
|
||||
select
|
||||
a.id as id,
|
||||
a.id as name,
|
||||
a.state as state,
|
||||
sum(l.unit_amount) as quantity,
|
||||
sum(l.amount) as balance,
|
||||
a.partner_id as partner_id,
|
||||
a.quantity_max as quantity_max,
|
||||
a.date as date_deadline
|
||||
from
|
||||
account_analytic_line l
|
||||
right join
|
||||
account_analytic_account a on (l.account_id=a.id)
|
||||
group by
|
||||
a.id,a.state, a.quantity_max,a.date,a.partner_id
|
||||
having
|
||||
(a.quantity_max>0 and (sum(l.unit_amount)>=a.quantity_max)) or
|
||||
a.date <= current_date
|
||||
)""")
|
||||
|
||||
class report_account_analytic_line_to_invoice(osv.osv):
|
||||
_name = "report.account.analytic.line.to.invoice"
|
||||
_description = "Analytic lines to invoice report"
|
||||
_auto = False
|
||||
_columns = {
|
||||
'name': fields.char('Year', required=False, readonly=True),
|
||||
'product_id':fields.many2one('product.product', 'Product', readonly=True),
|
||||
'account_id':fields.many2one('account.analytic.account', 'Analytic account', readonly=True),
|
||||
'product_uom_id':fields.many2one('product.uom', 'Unit of Measure', readonly=True),
|
||||
'unit_amount': fields.float('Units', readonly=True),
|
||||
'sale_price': fields.float('Sale price', readonly=True, digits_compute=dp.get_precision('Product Price')),
|
||||
'amount': fields.float('Amount', readonly=True, digits=0),
|
||||
'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),
|
||||
}
|
||||
_order = 'name desc, product_id asc, account_id asc'
|
||||
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_account_analytic_line_to_invoice')
|
||||
cr.execute("""
|
||||
CREATE OR REPLACE VIEW report_account_analytic_line_to_invoice AS (
|
||||
SELECT
|
||||
DISTINCT(to_char(l.date,'MM')) as month,
|
||||
to_char(l.date, 'YYYY') as name,
|
||||
MIN(l.id) AS id,
|
||||
l.product_id,
|
||||
l.account_id,
|
||||
SUM(l.amount) AS amount,
|
||||
SUM(l.unit_amount*t.list_price) AS sale_price,
|
||||
SUM(l.unit_amount) AS unit_amount,
|
||||
l.product_uom_id
|
||||
FROM
|
||||
account_analytic_line l
|
||||
left join
|
||||
product_product p on (l.product_id=p.id)
|
||||
left join
|
||||
product_template t on (p.product_tmpl_id=t.id)
|
||||
WHERE
|
||||
(invoice_id IS NULL) and (to_invoice IS NOT NULL)
|
||||
GROUP BY
|
||||
to_char(l.date, 'YYYY'), to_char(l.date,'MM'), product_id, product_uom_id, account_id
|
||||
)
|
||||
""")
|
||||
@@ -1,138 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Analytic accounts to close -->
|
||||
<record id="view_analytic_account_close_form" model="ir.ui.view">
|
||||
<field name="name">report.analytic.account.close.form</field>
|
||||
<field name="model">report.analytic.account.close</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Expired analytic accounts">
|
||||
<group col="4">
|
||||
<field name="name" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="quantity"/>
|
||||
<field name="state"/>
|
||||
<field name="quantity_max"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="balance"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_analytic_account_close_tree" model="ir.ui.view">
|
||||
<field name="name">report.analytic.account.close.tree</field>
|
||||
<field name="model">report.analytic.account.close</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Expired analytic accounts">
|
||||
<field name="name" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="state"/>
|
||||
<field name="quantity"/>
|
||||
<field name="quantity_max"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="balance"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_analytic_account_graph" model="ir.ui.view">
|
||||
<field name="name">report.analytic.account.close.graph</field>
|
||||
<field name="model">report.analytic.account.close</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Expired analytic accounts" type="bar">
|
||||
<field name="partner_id"/>
|
||||
<field name="quantity" operator="+"/>
|
||||
<field name="quantity_max" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_analytic_account_tree" model="ir.actions.act_window">
|
||||
<field name="name">Expired analytic accounts</field>
|
||||
<field name="res_model">report.analytic.account.close</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="domain">[('state','=','open')]</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_line_to_invoice_view_form" model="ir.ui.view">
|
||||
<field name="name">report.account.analytic.line.to.invoice</field>
|
||||
<field name="model">report.account.analytic.line.to.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Analytic Lines to Invoice">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<newline/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_uom_id"/>
|
||||
<newline/>
|
||||
<field colspan="1" name="amount" widget="monetary"/>
|
||||
<field colspan="1" name="unit_amount"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_line_to_invoice_view_tree" model="ir.ui.view">
|
||||
<field name="name">report.account.analytic.line.to.invoice</field>
|
||||
<field name="model">report.account.analytic.line.to.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Analytic Lines to Invoice">
|
||||
<field name="name"/>
|
||||
<field name="month"/>
|
||||
<field name="product_id"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="amount" widget="monetary"/>
|
||||
<field name="sale_price"/>
|
||||
<field name="unit_amount"/>
|
||||
<field name="product_uom_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_line_to_invoice_view_graph" model="ir.ui.view">
|
||||
<field name="name">report.account.analytic.line.to.invoice.graph</field>
|
||||
<field name="model">report.account.analytic.line.to.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Analytic Lines to Invoice" type="bar">
|
||||
<field name="name"/>
|
||||
<field name="sale_price" operator="+"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_analytic_line_to_invoice_view_filter" model="ir.ui.view">
|
||||
<field name="name">report.account.analytic.line.to.invoice.select</field>
|
||||
<field name="model">report.account.analytic.line.to.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Analytic Lines to Invoice">
|
||||
<field name="name" string="Analytic Lines"/>
|
||||
<field name="month"/>
|
||||
<field name="product_id"/>
|
||||
<field name="account_id" groups="analytic.group_analytic_accounting"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_analytic_line_to_invoice" model="ir.actions.act_window">
|
||||
<field name="name">Analytic Lines to Invoice</field>
|
||||
<field name="res_model">report.account.analytic.line.to.invoice</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="search_view_id" ref="account_analytic_line_to_invoice_view_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="act_acc_analytic_acc_2_report_acc_analytic_line_to_invoice" model="ir.actions.act_window">
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'search_default_account_id': [active_id], 'default_account_id': active_id,'search_default_to_invoice': 1}</field>
|
||||
<field name="name">To Invoice</field>
|
||||
<field name="res_model">account.analytic.line</field>
|
||||
<field name="src_model">account.analytic.account</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,16 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_hr_timesheet_invoice_factor_hr_user,hr_timesheet_invoice.factor.hr.user,model_hr_timesheet_invoice_factor,base.group_hr_user,1,1,1,1
|
||||
access_hr_timesheet_invoice_factor_employee,hr_timesheet_invoice.factor.hr.user,model_hr_timesheet_invoice_factor,base.group_user,1,1,1,1
|
||||
access_hr_timesheet_invoice_factor_acc_inv,hr_timesheet_invoice.factor.account.invoice,model_hr_timesheet_invoice_factor,account.group_account_invoice,1,1,1,1
|
||||
access_report_analytic_account_close,report.analytic.account.close,model_report_analytic_account_close,account.group_account_manager,1,0,0,0
|
||||
access_report_account_analytic_line_to_invoice,report.account.analytic.line.to.invoice,model_report_account_analytic_line_to_invoice,account.group_account_manager,1,0,0,0
|
||||
access_report_timesheet_user,report_timesheet.user,model_report_timesheet_user,base.group_hr_manager,1,1,1,1
|
||||
access_report_timesheet_account,report_timesheet.account,model_report_timesheet_account,base.group_hr_manager,1,1,1,1
|
||||
access_report_timesheet_account_date,report_timesheet.account.date,model_report_timesheet_account_date,base.group_hr_manager,1,1,1,1
|
||||
access_report_timesheet_invoice,report_timesheet.invoice,model_report_timesheet_invoice,base.group_hr_manager,1,1,1,1
|
||||
access_report_analytic_account_close_manager,report.analytic.account.close.manager,model_report_analytic_account_close,base.group_hr_manager,1,1,1,1
|
||||
access_report_account_analytic_line_to_invoice_manager,report.account.analytic.line.to.invoice.manager,model_report_account_analytic_line_to_invoice,base.group_hr_manager,1,1,1,1
|
||||
access_account_invoice_hr_user,account.invoice.hr.user,account.model_account_invoice,base.group_hr_user,1,1,1,1
|
||||
access_account_invoice_tax_hr_manager,account.invoice.tax.hr.manager,account.model_account_invoice_tax,base.group_hr_manager,1,1,1,1
|
||||
access_report_timesheet_line_employee,report.timesheet.line.employee,model_report_timesheet_line,base.group_hr_user,1,1,1,1
|
||||
access_report_timesheet_line_employee_user,report.timesheet.line,model_report_timesheet_line,base.group_user,1,1,1,0
|
||||
|
@@ -1,11 +0,0 @@
|
||||
-
|
||||
In order to test the PDF reports defined on HR Timesheet Account Analytic Profit, we will print report of HR Timesheet Account Analytic Profit
|
||||
-
|
||||
!python {model: account.analytic.line}: |
|
||||
import os, time
|
||||
import openerp.report
|
||||
from openerp import tools
|
||||
data_dict = {'model': 'ir.ui.menu', 'form': {'date_from': time.strftime('%Y-%m-01'), 'employee_ids': [[6,0,[ref('hr.employee_fp'), ref('hr.employee_qdp'),ref('hr.employee_al')]]], 'journal_ids': [[6,0,[ref('hr_timesheet.analytic_journal')]]], 'date_to': time.strftime('%Y-%m-%d')}}
|
||||
data, format = openerp.report.render_report(cr, uid, [], 'hr_timesheet_invoice.report_analyticprofit', data_dict, {})
|
||||
if tools.config['test_report_directory']:
|
||||
file(os.path.join(tools.config['test_report_directory'], 'hr_timesheet_invoice-account_analytic_profit_report.'+format), 'wb+').write(data)
|
||||
@@ -1,170 +0,0 @@
|
||||
-
|
||||
In order to test hr_timesheet_invoice in OpenERP, I create account line to manage invoice based on costs.
|
||||
-
|
||||
I create an account analytic line.
|
||||
-
|
||||
!record {model: account.analytic.line, id: account_analytic_line_developyamlforhrmodule0 }:
|
||||
account_id: analytic.analytic_agrolait
|
||||
amount: -1.0
|
||||
general_account_id: a_expense
|
||||
journal_id: hr_timesheet.analytic_journal
|
||||
name: develop yaml for hr module
|
||||
product_id: product.product_product_1
|
||||
product_uom_id: product.product_uom_hour
|
||||
to_invoice: hr_timesheet_invoice.timesheet_invoice_factor2
|
||||
unit_amount: 5.00
|
||||
-
|
||||
Assign partner name and price list in analytic account.
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic.analytic_agrolait}:
|
||||
partner_id: base.res_partner_2
|
||||
pricelist_id: product.list0
|
||||
-
|
||||
I open this account and make the state as pending.
|
||||
-
|
||||
!python {model: account.analytic.account}: |
|
||||
self.set_open(cr, uid, [ref('analytic.analytic_agrolait')], None)
|
||||
self.set_pending(cr, uid, [ref('analytic.analytic_agrolait')], None)
|
||||
-
|
||||
I assign account on analytic account line.
|
||||
-
|
||||
!python {model: account.analytic.line}: |
|
||||
self.on_change_account_id(cr, uid, [ref('account_analytic_line_developyamlforhrmodule0')], ref('analytic.analytic_agrolait'))
|
||||
|
||||
-
|
||||
I create a Tax
|
||||
-
|
||||
!record {model: account.tax, id: tax10}:
|
||||
name: Tax 10.0
|
||||
amount: 10.0
|
||||
amount_type: fixed
|
||||
sequence: 1
|
||||
company_id: base.main_company
|
||||
type_tax_use: sale
|
||||
-
|
||||
I create an Account with the tax
|
||||
-
|
||||
!record {model: account.account, id: account_income_i000}:
|
||||
name: "income account"
|
||||
code: "I000"
|
||||
user_type_id: "account.data_account_type_revenue"
|
||||
tax_ids: [tax10]
|
||||
-
|
||||
I set the account as property_account_income_id on the product and I set the tax on the product
|
||||
-
|
||||
!record {model: product.product, id: product.product_product_1, view: False}:
|
||||
property_account_income_id: account_income_i000
|
||||
uom_id: product.product_uom_hour
|
||||
taxes_id: [tax10]
|
||||
list_price: 75
|
||||
-
|
||||
I create invoice on analytic Line using "Invoice analytic Line" wizard.
|
||||
-
|
||||
!record {model: hr.timesheet.invoice.create, id: hr_timesheet_invoice_create_0}:
|
||||
date: 1
|
||||
name: 1
|
||||
price: 1
|
||||
product: product.product_product_1
|
||||
time: 1
|
||||
-
|
||||
I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice.
|
||||
-
|
||||
!python {model: hr.timesheet.invoice.create}: |
|
||||
action_result = self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], {
|
||||
"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0")]
|
||||
})
|
||||
invoice_pool = self.pool.get('account.invoice')
|
||||
invoice_domain = action_result['domain']
|
||||
invoice_ids = invoice_pool.search(cr, uid, invoice_domain)
|
||||
invoice_pool.write(cr, uid, invoice_ids, {'origin': 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) \
|
||||
+ '_aaldyfhrm0_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0") ) })
|
||||
|
||||
-
|
||||
I check that Invoice is created for this timesheet.
|
||||
-
|
||||
!python {model: account.analytic.line}: |
|
||||
from openerp.tools import float_compare
|
||||
aline = self.browse(cr, uid, ref('account_analytic_line_developyamlforhrmodule0'))
|
||||
analytic_account_obj = self.pool.get('account.analytic.account')
|
||||
data = self.pool.get('hr.timesheet.invoice.create').read(cr, uid, [ref("hr_timesheet_invoice_create_0")], [], context)[0]
|
||||
partner = aline.account_id.partner_id.id
|
||||
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner),
|
||||
('origin', '=', 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) + '_aaldyfhrm0_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule0") ))
|
||||
])
|
||||
invoice_id = invoice_obj.browse(cr, uid, invoice_ids)[0]
|
||||
|
||||
for invoice in invoice_id.invoice_line_ids:
|
||||
product = invoice.product_id.id
|
||||
|
||||
product_exp = data['product'][0]
|
||||
|
||||
assert product == product_exp
|
||||
assert aline.invoice_id, "Invoice created, but analytic line wasn't updated."
|
||||
assert aline.invoice_id == invoice_id, "Invoice doesn't match the one at analytic line"
|
||||
assert float_compare(invoice_id.amount_untaxed, 187.5, precision_digits=2) == 0, "Invoice amount mismatch: %s" % invoice_id.amount_untaxed
|
||||
assert float_compare(invoice_id.amount_tax, 50, precision_digits=2) == 0, "Invoice tax mismatch: %s" % invoice_id.amount_tax
|
||||
|
||||
-
|
||||
In order to test group invoicing by customer.
|
||||
-
|
||||
I create an analytic account 'Sales Integration' for customer Asustek.
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic_asustek01}:
|
||||
name: Sales Integration
|
||||
partner_id: base.res_partner_1
|
||||
-
|
||||
I create an analytic account 'Asustek Website' for customer Asustek.
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic_asustek02}:
|
||||
name: Asustek Website
|
||||
partner_id: base.res_partner_1
|
||||
-
|
||||
I create an account analytic line.
|
||||
-
|
||||
!record {model: account.analytic.line, id: account_analytic_line_0 }:
|
||||
account_id: analytic_asustek01
|
||||
amount: -1.0
|
||||
general_account_id: a_expense
|
||||
journal_id: hr_timesheet.analytic_journal
|
||||
name: sales module extension
|
||||
product_id: product.product_product_1
|
||||
product_uom_id: product.product_uom_hour
|
||||
to_invoice: hr_timesheet_invoice.timesheet_invoice_factor2
|
||||
unit_amount: 5.00
|
||||
-
|
||||
I create an account analytic line.
|
||||
-
|
||||
!record {model: account.analytic.line, id: account_analytic_line_3 }:
|
||||
account_id: analytic_asustek02
|
||||
amount: -1.0
|
||||
general_account_id: a_expense
|
||||
journal_id: hr_timesheet.analytic_journal
|
||||
name: template design
|
||||
product_id: product.product_product_1
|
||||
product_uom_id: product.product_uom_hour
|
||||
to_invoice: hr_timesheet_invoice.timesheet_invoice_factor2
|
||||
unit_amount: 5.00
|
||||
-
|
||||
Now I create invoice on analytic Line using "Invoice analytic Line" wizard and set group by partner true.
|
||||
-
|
||||
!record {model: hr.timesheet.invoice.create, id: hr_timesheet_invoice_create_1}:
|
||||
date: 1
|
||||
name: 1
|
||||
product: product.product_product_1
|
||||
time: 1
|
||||
group_by_partner: 1
|
||||
-
|
||||
I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice and check that only one invoice is created for customer Asustek.
|
||||
-
|
||||
!python {model: hr.timesheet.invoice.create}: |
|
||||
action_result = self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_1")], {
|
||||
"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_0"),ref("hr_timesheet_invoice.account_analytic_line_3")]
|
||||
})
|
||||
invoice_pool = self.pool.get('account.invoice')
|
||||
invoice_domain = action_result['domain']
|
||||
invoice_ids = invoice_pool.search(cr, uid, invoice_domain)
|
||||
invoice_id = invoice_pool.browse(cr, uid, invoice_ids)[0]
|
||||
assert len(invoice_ids) == 1,"only one invoice should be created for customer Asustek."
|
||||
assert invoice_id.amount_untaxed == 375.0, "Invoice amount mismatch: %s" % invoice_id.amount_untaxed
|
||||
@@ -1,106 +0,0 @@
|
||||
-
|
||||
In order to test hr_timesheet_invoice in OpenERP, I create account line to manage invoice based on costs.
|
||||
-
|
||||
I create an account analytic line.
|
||||
-
|
||||
!record {model: account.analytic.line, id: account_analytic_line_developyamlforhrmodule1 }:
|
||||
account_id: analytic.analytic_agrolait
|
||||
amount: -1.0
|
||||
general_account_id: a_expense
|
||||
journal_id: hr_timesheet.analytic_journal
|
||||
name: develop yaml for hr module
|
||||
product_id: product.product_product_1
|
||||
product_uom_id: product.product_uom_hour
|
||||
to_invoice: hr_timesheet_invoice.timesheet_invoice_factor2
|
||||
unit_amount: 5.00
|
||||
-
|
||||
Assign partner name and price list in analytic account.
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic.analytic_agrolait}:
|
||||
partner_id: base.res_partner_2
|
||||
pricelist_id: product.list0
|
||||
-
|
||||
I open this account and make the state as pending.
|
||||
-
|
||||
!python {model: account.analytic.account}: |
|
||||
self.set_open(cr, uid, [ref('analytic.analytic_agrolait')], None)
|
||||
self.set_pending(cr, uid, [ref('analytic.analytic_agrolait')], None)
|
||||
-
|
||||
I assign account on analytic account line.
|
||||
-
|
||||
!python {model: account.analytic.line}: |
|
||||
self.on_change_account_id(cr, uid, [ref('account_analytic_line_developyamlforhrmodule1')], ref('analytic.analytic_agrolait'))
|
||||
-
|
||||
I create a Tax
|
||||
-
|
||||
!record {model: account.tax, id: tax8}:
|
||||
name: Tax 8.0
|
||||
amount: 8.0
|
||||
amount_type: fixed
|
||||
sequence: 1
|
||||
company_id: base.main_company
|
||||
type_tax_use: sale
|
||||
-
|
||||
I create an Account with the tax
|
||||
-
|
||||
!record {model: account.account, id: account_income_i000}:
|
||||
name: "income account"
|
||||
code: "I000"
|
||||
user_type_id: "account.data_account_type_revenue"
|
||||
tax_ids: [tax8]
|
||||
-
|
||||
I set the account as property_account_income_id on the product and I set no tax on the product (so default tax from the account will be used)
|
||||
-
|
||||
!record {model: product.product, id: product.product_product_1, view: False}:
|
||||
property_account_income_id: account_income_i000
|
||||
uom_id: product.product_uom_hour
|
||||
taxes_id: []
|
||||
list_price: 75
|
||||
-
|
||||
I create invoice on analytic Line using "Invoice analytic Line" wizard.
|
||||
-
|
||||
!record {model: hr.timesheet.invoice.create, id: hr_timesheet_invoice_create_0}:
|
||||
date: 1
|
||||
name: 1
|
||||
price: 1
|
||||
product: product.product_product_1
|
||||
time: 1
|
||||
-
|
||||
I click on "Create Invoice" button of "Invoice analytic Line" wizard to create invoice.
|
||||
-
|
||||
!python {model: hr.timesheet.invoice.create}: |
|
||||
action_result = self.do_create(cr, uid, [ref("hr_timesheet_invoice_create_0")], {
|
||||
"active_ids": [ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1")]
|
||||
})
|
||||
invoice_pool = self.pool.get('account.invoice')
|
||||
invoice_domain = action_result['domain']
|
||||
invoice_ids = invoice_pool.search(cr, uid, invoice_domain)
|
||||
invoice_pool.write(cr, uid, invoice_ids, {'origin': 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0"))\
|
||||
+ '_aaldyfhrm1_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1") ) })
|
||||
-
|
||||
I check that Invoice is created for this timesheet.
|
||||
-
|
||||
!python {model: account.analytic.line}: |
|
||||
from openerp.tools import float_compare
|
||||
aline = self.browse(cr, uid, ref('account_analytic_line_developyamlforhrmodule1'))
|
||||
analytic_account_obj = self.pool.get('account.analytic.account')
|
||||
data = self.pool.get('hr.timesheet.invoice.create').read(cr, uid, [ref("hr_timesheet_invoice_create_0")], [], context)[0]
|
||||
partner = aline.account_id.partner_id.id
|
||||
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
invoice_ids = invoice_obj.search(cr, uid, [('partner_id', '=', partner),
|
||||
('origin', '=', 'test-hrtsic0_id_'+str( ref("hr_timesheet_invoice_create_0")) + '_aaldyfhrm1_id_'+str( ref("hr_timesheet_invoice.account_analytic_line_developyamlforhrmodule1") ))
|
||||
])
|
||||
|
||||
invoice_id = invoice_obj.browse(cr, uid, invoice_ids)[0]
|
||||
|
||||
for invoice in invoice_id.invoice_line_ids:
|
||||
product = invoice.product_id.id
|
||||
|
||||
product_exp = data['product'][0]
|
||||
|
||||
assert product == product_exp
|
||||
assert aline.invoice_id, "Invoice created, but analytic line wasn't updated."
|
||||
assert aline.invoice_id == invoice_id, "Invoice doesn't match the one at analytic line"
|
||||
assert float_compare(invoice_id.amount_untaxed, 187.5, precision_digits=2) == 0, "Invoice amount mismatch: %s" % invoice_id.amount_untaxed
|
||||
assert float_compare(invoice_id.amount_tax, 40, precision_digits=2) == 0, "Invoice tax mismatch: %s" % invoice_id.amount_tax
|
||||
@@ -1 +0,0 @@
|
||||
from . import test_invoice
|
||||
@@ -1,103 +0,0 @@
|
||||
from openerp.addons.account.tests.account_test_classes import AccountingTestCase
|
||||
|
||||
class TestInvoice(AccountingTestCase):
|
||||
"""Tests to generate invoices from analytic lines
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestInvoice, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.account_invoice = self.registry('account.invoice')
|
||||
self.account_analytic_account = self.registry('account.analytic.account')
|
||||
self.account_analytic_line = self.registry('account.analytic.line')
|
||||
self.product_product = self.registry('product.product')
|
||||
|
||||
self.think_big_id = self.registry("ir.model.data").get_object_reference(cr, uid, "base", "res_partner_18")[1]
|
||||
self.timesheet_journal_id = self.registry("ir.model.data").get_object_reference(cr, uid, "hr_timesheet", "analytic_journal")[1]
|
||||
self.expense_journal_id = self.registry("ir.model.data").get_object_reference(cr, uid, 'account', 'exp')[1]
|
||||
user_type_id = self.ref('account.data_account_type_expenses')
|
||||
self.expense_account_id = self.env['account.account'].create({'code': 'X2120', 'name': 'Test Expense Account', 'user_type_id': user_type_id}).id
|
||||
self.factor_100_id = self.registry("ir.model.data").get_object_reference(cr, uid, "hr_timesheet_invoice", "timesheet_invoice_factor1")[1]
|
||||
|
||||
self.potato_account_id = self.account_analytic_account.create(cr, uid, {
|
||||
'name': 'Potatoes Project',
|
||||
'partner_id': self.think_big_id,
|
||||
'type': 'contract',
|
||||
'state': 'open',
|
||||
})
|
||||
self.carrot_account_id = self.account_analytic_account.create(cr, uid, {
|
||||
'name': 'Carrot & Development',
|
||||
'partner_id': self.think_big_id,
|
||||
'type': 'contract',
|
||||
'state': 'open',
|
||||
})
|
||||
self.potato_id = self.product_product.create(cr, uid, {
|
||||
'name': 'Potato',
|
||||
'list_price': 2,
|
||||
})
|
||||
self.carrot_id = self.product_product.create(cr, uid, {
|
||||
'name': 'Carrot',
|
||||
'list_price': 3,
|
||||
})
|
||||
|
||||
def test_single_invoice(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
first_line = {
|
||||
'name': 'One potato',
|
||||
'amount': 2,
|
||||
'unit_amount': 1,
|
||||
'product_id': self.potato_id,
|
||||
'account_id': self.potato_account_id,
|
||||
'general_account_id': self.expense_account_id,
|
||||
'journal_id': self.expense_journal_id,
|
||||
'partner_id': self.think_big_id,
|
||||
'to_invoice': self.factor_100_id,
|
||||
}
|
||||
second_line = {
|
||||
'name': 'Two carrots',
|
||||
'amount': 6,
|
||||
'unit_amount': 2,
|
||||
'product_id': self.carrot_id,
|
||||
'account_id': self.carrot_account_id,
|
||||
'general_account_id': self.expense_account_id,
|
||||
'journal_id': self.expense_journal_id,
|
||||
'partner_id': self.think_big_id,
|
||||
'to_invoice': self.factor_100_id,
|
||||
}
|
||||
first_line_id = self.account_analytic_line.create(cr, uid, first_line)
|
||||
second_line_id = self.account_analytic_line.create(cr, uid, second_line)
|
||||
|
||||
data = {'group_by_partner': False, 'date': True, 'name': True}
|
||||
invoice_ids = self.account_analytic_line.invoice_cost_create(cr, uid, [first_line_id, second_line_id], data)
|
||||
self.assertEquals(len(invoice_ids), 2)
|
||||
for invoice in self.account_invoice.browse(cr, uid, invoice_ids[0]):
|
||||
self.assertEquals(len(invoice.invoice_line_ids), 1)
|
||||
line = invoice.invoice_line_ids[0]
|
||||
if line.product_id.id == self.potato_id:
|
||||
self.assertEquals(line.account_analytic_id.id, self.potato_account_id)
|
||||
self.assertEquals(line.price_unit, -2)
|
||||
self.assertEquals(line.quantity, 1)
|
||||
else:
|
||||
self.assertEquals(line.product_id.id, self.carrot_id)
|
||||
self.assertEquals(line.account_analytic_id.id, self.carrot_account_id)
|
||||
self.assertEquals(line.price_unit, -3)
|
||||
self.assertEquals(line.quantity, 2)
|
||||
|
||||
data = {'group_by_partner': True, 'date': True, 'name': True}
|
||||
first_line_id = self.account_analytic_line.create(cr, uid, first_line)
|
||||
second_line_id = self.account_analytic_line.create(cr, uid, second_line)
|
||||
invoice_ids = self.account_analytic_line.invoice_cost_create(cr, uid, [first_line_id, second_line_id], data)
|
||||
self.assertEquals(len(invoice_ids), 1)
|
||||
invoice = self.account_invoice.browse(cr, uid, invoice_ids[0])
|
||||
self.assertEquals(len(invoice.invoice_line_ids), 2)
|
||||
for line in invoice.invoice_line_ids:
|
||||
if line.product_id.id == self.potato_id:
|
||||
self.assertEquals(line.account_analytic_id.id, self.potato_account_id)
|
||||
self.assertEquals(line.price_unit, -2)
|
||||
self.assertEquals(line.quantity, 1)
|
||||
else:
|
||||
self.assertEquals(line.product_id.id, self.carrot_id)
|
||||
self.assertEquals(line.account_analytic_id.id, self.carrot_account_id)
|
||||
self.assertEquals(line.price_unit, -3)
|
||||
self.assertEquals(line.quantity, 2)
|
||||
@@ -1,84 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<template id="report_analyticprofit">
|
||||
<t t-call="report.html_container">
|
||||
<t t-call="report.external_layout">
|
||||
<div class="page">
|
||||
<h2>Invoice rate by user</h2>
|
||||
|
||||
<div class="row mt32 mb32">
|
||||
<div class="col-xs-3">
|
||||
<strong>Period from startdate:</strong>
|
||||
<p t-esc="formatLang(data['form']['date_from'],date=True)"/>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong>Period to enddate:</strong>
|
||||
<p t-esc="formatLang(data['form']['date_to'],date=True)"/>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong>Currency:</strong>
|
||||
<p t-esc="res_company.currency_id.name"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User or Journal Name</th>
|
||||
<th>Units</th>
|
||||
<th>Theorical</th>
|
||||
<th>Income</th>
|
||||
<th>Cost</th>
|
||||
<th>Profit</th>
|
||||
<th>Eff.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbdody>
|
||||
<tr>
|
||||
<td>Totals:</td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['unit_amount'], line(data['form'], data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)"/></td>
|
||||
<td></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['amount'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['cost'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['profit'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['cost'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0) and round(reduce(lambda x, y: x+y['amount'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)/reduce(lambda x, y: x+y['cost'], line(data['form'],data['form']['journal_ids'][0][2], data['form']['employee_ids'][0][2]), 0)* -100, 2)"/><span> %</span></td>
|
||||
</tr>
|
||||
<t t-foreach="user_ids(lines(data['form']))" t-as="e">
|
||||
<t t-foreach="journal_ids(data['form'], [e.id])" t-as="j">
|
||||
<tr>
|
||||
<td><span t-esc="e.name"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['unit_amount'], line(data['form'], [j.id], [e.id]), 0) "/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['amount_th'], line(data['form'], [j.id], [e.id]), 0)"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['amount'], line(data['form'], [j.id], [e.id]), 0)"/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['cost'], line(data['form'], [j.id], [e.id]), 0) "/></td>
|
||||
<td><span t-esc="reduce(lambda x, y: x+y['profit'], line(data['form'], [j.id], [e.id]), 0)"/></td>
|
||||
<td>
|
||||
<t t-if="reduce(lambda x, y: x+y['cost'], line(data['form'], [j.id], [e.id]), 0)">
|
||||
<span t-esc="reduce(lambda x, y: x+y['amount'], line(data['form'], [j.id], [e.id]), 0) / reduce(lambda x, y: x+y['cost'], line(data['form'], [j.id], [e.id]), 0) * -100.0"/>
|
||||
<span> %</span>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="7"><span t-esc="j.name"/></th>
|
||||
</tr>
|
||||
<tr t-foreach="line(data['form'], [j.id],[e.id])" t-as="l">
|
||||
<td><span t-esc="l['name']"/></td>
|
||||
<td><span t-esc="l['unit_amount']"/></td>
|
||||
<td><span t-esc="l['amount_th']"/></td>
|
||||
<td><span t-esc="l['amount']"/></td>
|
||||
<td><span t-esc="l['cost']"/></td>
|
||||
<td><span t-esc="l['profit']"/></td>
|
||||
<td><span t-esc="l['eff']"/><span> %</span></td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
</tbdody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import hr_timesheet_invoice_create
|
||||
import hr_timesheet_analytic_profit
|
||||
import hr_timesheet_final_invoice_create
|
||||
@@ -1,53 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import datetime
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class account_analytic_profit(osv.osv_memory):
|
||||
_name = 'hr.timesheet.analytic.profit'
|
||||
_description = 'Print Timesheet Profit'
|
||||
_columns = {
|
||||
'date_from': fields.date('From', required=True),
|
||||
'date_to': fields.date('To', required=True),
|
||||
'journal_ids': fields.many2many('account.analytic.journal', 'analytic_profit_journal_rel', 'analytic_id', 'journal_id', 'Journal', required=True),
|
||||
'employee_ids': fields.many2many('res.users', 'analytic_profit_emp_rel', 'analytic_id', 'emp_id', 'User', required=True),
|
||||
}
|
||||
|
||||
def _date_from(*a):
|
||||
return datetime.date.today().replace(day=1).strftime('%Y-%m-%d')
|
||||
|
||||
def _date_to(*a):
|
||||
return datetime.date.today().strftime('%Y-%m-%d')
|
||||
|
||||
_defaults = {
|
||||
'date_from': _date_from,
|
||||
'date_to': _date_to
|
||||
}
|
||||
|
||||
def print_report(self, cr, uid, ids, context=None):
|
||||
line_obj = self.pool.get('account.analytic.line')
|
||||
data = {}
|
||||
data['form'] = self.read(cr, uid , ids, context=context)[0]
|
||||
ids_chk = line_obj.search(cr, uid, [
|
||||
('date', '>=', data['form']['date_from']),
|
||||
('date', '<=', data['form']['date_to']),
|
||||
('journal_id', 'in', data['form']['journal_ids']),
|
||||
('user_id', 'in', data['form']['employee_ids']),
|
||||
], context=context)
|
||||
if not ids_chk:
|
||||
raise UserError(_('No record(s) found for this report.'))
|
||||
|
||||
data['form']['journal_ids'] = [(6, 0, data['form']['journal_ids'])] # Improve me => Change the rml/sxw so that it can support withou [0][2]
|
||||
data['form']['employee_ids'] = [(6, 0, data['form']['employee_ids'])]
|
||||
datas = {
|
||||
'ids': [],
|
||||
'model': 'account.analytic.line',
|
||||
'form': data['form']
|
||||
}
|
||||
return self.pool['report'].get_action(
|
||||
cr, uid, [], 'hr_timesheet_invoice.report_analyticprofit', data=datas, context=context
|
||||
)
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_hr_timesheet_analytic_profit" model="ir.ui.view">
|
||||
<field name="name">Timesheet Profit</field>
|
||||
<field name="model">hr.timesheet.analytic.profit</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Timesheet Profit">
|
||||
<sheet>
|
||||
<group>
|
||||
<label for="date_from" string="Duration" />
|
||||
<div>
|
||||
<field name="date_from" nolabel="1" class="oe_inline" />
|
||||
- <field name="date_to" nolabel="1" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="journal_ids" widget="many2many_tags"/>
|
||||
<field name="employee_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button name="print_report" string="Print" colspan="1" type="object" class="btn-primary"/>
|
||||
<button special="cancel" string="Cancel" class="btn-default"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_timesheet_analytic_profit" model="ir.actions.act_window">
|
||||
<field name="name">Timesheet Profit</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">hr.timesheet.analytic.profit</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_hr_timesheet_analytic_profit"
|
||||
id="menu_hr_timesheet_analytic_profit"
|
||||
parent="hr_timesheet.menu_timesheets_reports" sequence="3"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import time
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
#
|
||||
# Create an final invoice based on selected timesheet lines
|
||||
#
|
||||
|
||||
#
|
||||
# TODO: check unit of measure !!!
|
||||
#
|
||||
class final_invoice_create(osv.osv_memory):
|
||||
_name = 'hr.timesheet.invoice.create.final'
|
||||
_description = 'Create invoice from timesheet final'
|
||||
_columns = {
|
||||
'date': fields.boolean('Date', help='Display date in the history of works'),
|
||||
'time': fields.boolean('Time Spent', help='Display time in the history of works'),
|
||||
'name': fields.boolean('Log of Activity', help='Display detail of work in the invoice line.'),
|
||||
'price': fields.boolean('Cost', help='Display cost of the item you reinvoice'),
|
||||
'product': fields.many2one('product.product', 'Product', help='The product that will be used to invoice the remaining amount'),
|
||||
'group_by_partner': fields.boolean('Group by Partner', help="If this box is checked, the system will group invoices by customer."),
|
||||
}
|
||||
|
||||
def do_create(self, cr, uid, ids, context=None):
|
||||
data = self.read(cr, uid, ids, context=context)[0]
|
||||
# hack for fixing small issue (context should not propagate implicitly between actions)
|
||||
if 'default_type' in context:
|
||||
del context['default_type']
|
||||
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')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
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']
|
||||
act_win = act_obj.read(cr, uid, [res_id], context=context)[0]
|
||||
act_win['domain'] = [('id','in',invs),('type','=','out_invoice')]
|
||||
act_win['name'] = _('Invoices')
|
||||
return act_win
|
||||
@@ -1,53 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
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', 'Force Product', help='Fill this field only if you want to force the use a specific product. Keep empty to use the real product that comes from the cost.'),
|
||||
'group_by_partner': fields.boolean('Group by Partner', help='If this box is checked, the system will group invoices by customer.'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'date': 1,
|
||||
'name': 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', []) or []
|
||||
for analytic in analytic_obj.browse(cr, uid, data, context=context):
|
||||
if analytic.invoice_id:
|
||||
raise UserError(_("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]
|
||||
# Create an invoice based on selected timesheet lines
|
||||
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')
|
||||
act_obj = self.pool.get('ir.actions.act_window')
|
||||
mod_ids = mod_obj.search(cr, uid, [('name', '=', 'action_invoice_tree1')], context=context)
|
||||
res_id = mod_obj.read(cr, uid, mod_ids, ['res_id'], context=context)[0]['res_id']
|
||||
act_win = act_obj.read(cr, uid, [res_id], context=context)[0]
|
||||
act_win['domain'] = [('id','in',invs),('type','=','out_invoice')]
|
||||
act_win['name'] = _('Invoices')
|
||||
return act_win
|
||||
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="action_hr_timesheet_invoice_create_final" model="ir.actions.act_window">
|
||||
<field name="name">Create Invoice</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">hr.timesheet.invoice.create.final</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="multi" eval="1"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.values" id="hr_timesheet_invoice_create_final_values">
|
||||
<field name="model_id" ref="model_account_analytic_account" />
|
||||
<field name="name">Invoice</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="key">action</field>
|
||||
<field name="model">account.analytic.account</field>
|
||||
</record>
|
||||
|
||||
|
||||
<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="arch" type="xml">
|
||||
<form string="Invoice contract">
|
||||
<p>Show details in invoice lines</p>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="time"/>
|
||||
</group><group>
|
||||
<field name="name"/>
|
||||
<field name="price"/>
|
||||
</group>
|
||||
<group string="Force to use a special product" groups="base.group_no_one">
|
||||
<field name="product"/>
|
||||
</group>
|
||||
<group string="Create one invoice by partner">
|
||||
<field name="group_by_partner"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="do_create" string="Create Invoice" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-default" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_hr_timesheet_invoice_create" model="ir.ui.view">
|
||||
<field name="name">hr.timesheet.invoice.create.form</field>
|
||||
<field name="model">hr.timesheet.invoice.create</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Create Invoice">
|
||||
<group cols="2">
|
||||
<group string="Show details in invoice lines" colspan="1" cols="2">
|
||||
<field name="date"/>
|
||||
<field name="time"/>
|
||||
<field name="name"/>
|
||||
<field name="price"/>
|
||||
</group>
|
||||
<group string="Force to use a specific product" colspan="1" cols="2">
|
||||
<p class="oe_grey" colspan="2">When reinvoicing costs, the amount on the invoice lines is given by the sale price of the corresponding product (if any, and if its sale price is not 0). You can use the following field to enforce the use of a single product for all the chosen lines in the future invoices.</p>
|
||||
<field name="product"/>
|
||||
</group>
|
||||
<group string="Create one invoice by partner">
|
||||
<field name="group_by_partner"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="do_create" string="Create Invoices" type="object" class="btn-primary"/>
|
||||
<button string="Cancel" class="btn-default" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_hr_timesheet_invoice_create" model="ir.actions.act_window">
|
||||
<field name="name">Create Invoice</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">hr.timesheet.invoice.create</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.values" id="hr_timesheet_invoice_create_values">
|
||||
<field name="model_id" ref="model_account_analytic_line" />
|
||||
<field name="name">Create Invoice</field>
|
||||
<field name="key2">client_action_multi</field>
|
||||
<field name="value" eval="'ir.actions.act_window,' + str(ref('action_hr_timesheet_invoice_create'))" />
|
||||
<field name="key">action</field>
|
||||
<field name="model">account.analytic.line</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user