[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:
Nicolas Martinelli
2015-08-27 18:10:18 +02:00
parent e021a08b30
commit 9294e73e96
28 changed files with 0 additions and 2291 deletions
-5
View File
@@ -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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 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
3 access_hr_timesheet_invoice_factor_employee hr_timesheet_invoice.factor.hr.user model_hr_timesheet_invoice_factor base.group_user 1 1 1 1
4 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
5 access_report_analytic_account_close report.analytic.account.close model_report_analytic_account_close account.group_account_manager 1 0 0 0
6 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
7 access_report_timesheet_user report_timesheet.user model_report_timesheet_user base.group_hr_manager 1 1 1 1
8 access_report_timesheet_account report_timesheet.account model_report_timesheet_account base.group_hr_manager 1 1 1 1
9 access_report_timesheet_account_date report_timesheet.account.date model_report_timesheet_account_date base.group_hr_manager 1 1 1 1
10 access_report_timesheet_invoice report_timesheet.invoice model_report_timesheet_invoice base.group_hr_manager 1 1 1 1
11 access_report_analytic_account_close_manager report.analytic.account.close.manager model_report_analytic_account_close base.group_hr_manager 1 1 1 1
12 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
13 access_account_invoice_hr_user account.invoice.hr.user account.model_account_invoice base.group_hr_user 1 1 1 1
14 access_account_invoice_tax_hr_manager account.invoice.tax.hr.manager account.model_account_invoice_tax base.group_hr_manager 1 1 1 1
15 access_report_timesheet_line_employee report.timesheet.line.employee model_report_timesheet_line base.group_hr_user 1 1 1 1
16 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>