[MERGE] forward port of branch 8.0 up to 2492503
This commit is contained in:
@@ -266,7 +266,7 @@
|
||||
<group>
|
||||
<field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/>
|
||||
<field name="user_id" string="Responsible" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'account.group_account_invoice']}"/>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="name" attrs="{'invisible': [('type', '=', 'in_invoice')]}"/>
|
||||
<field name="payment_term" options="{'no_create': True}" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)"/>
|
||||
</group>
|
||||
<group>
|
||||
@@ -516,6 +516,19 @@
|
||||
<field name="search_view_id" ref="view_account_invoice_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="action_invoice_refund_out_tree_tree" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="act_window_id" ref="action_invoice_refund_out_tree"/>
|
||||
</record>
|
||||
|
||||
<record id="action_invoice_refund_out_tree_form" model="ir.actions.act_window.view">
|
||||
<field eval="2" name="sequence"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="invoice_form"/>
|
||||
<field name="act_window_id" ref="action_invoice_refund_out_tree"/>
|
||||
</record>
|
||||
|
||||
<record id="action_invoice_tree_pending_invoice" model="ir.actions.act_window">
|
||||
<field name="name">Pending Invoice</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
|
||||
@@ -851,7 +851,12 @@ class account_move_line(osv.osv):
|
||||
ret.append(ret_line)
|
||||
return ret
|
||||
|
||||
def list_partners_to_reconcile(self, cr, uid, context=None):
|
||||
|
||||
def list_partners_to_reconcile(self, cr, uid, context=None, filter_domain=False):
|
||||
line_ids = []
|
||||
if filter_domain:
|
||||
line_ids = self.search(cr, uid, filter_domain, context=context)
|
||||
where_clause = filter_domain and "AND l.id = ANY(%s)" or ""
|
||||
cr.execute(
|
||||
"""SELECT partner_id FROM (
|
||||
SELECT l.partner_id, p.last_reconciliation_date, SUM(l.debit) AS debit, SUM(l.credit) AS credit, MAX(l.create_date) AS max_date
|
||||
@@ -861,10 +866,12 @@ class account_move_line(osv.osv):
|
||||
WHERE a.reconcile IS TRUE
|
||||
AND l.reconcile_id IS NULL
|
||||
AND l.state <> 'draft'
|
||||
%s
|
||||
GROUP BY l.partner_id, p.last_reconciliation_date
|
||||
) AS s
|
||||
WHERE debit > 0 AND credit > 0 AND (last_reconciliation_date IS NULL OR max_date > last_reconciliation_date)
|
||||
ORDER BY last_reconciliation_date""")
|
||||
ORDER BY last_reconciliation_date"""
|
||||
% where_clause, (line_ids,))
|
||||
ids = [x[0] for x in cr.fetchall()]
|
||||
if not ids:
|
||||
return []
|
||||
|
||||
@@ -1791,7 +1791,7 @@ openerp.account = function (instance) {
|
||||
this.last_group_by = group_by;
|
||||
this.old_search = _.bind(this._super, this);
|
||||
var mod = new instance.web.Model("account.move.line", context, domain);
|
||||
return mod.call("list_partners_to_reconcile", []).then(function(result) {
|
||||
return mod.call("list_partners_to_reconcile", [context, domain]).then(function(result) {
|
||||
var current = self.current_partner !== null ? self.partners[self.current_partner][0] : null;
|
||||
self.partners = result;
|
||||
var index = _.find(_.range(self.partners.length), function(el) {
|
||||
|
||||
@@ -396,7 +396,7 @@ class crm_lead(format_address, osv.osv):
|
||||
"""
|
||||
stages_leads = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 0.0), ('fold', '=', True), ('sequence', '>', 1)], context=context)
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 0.0), ('on_change', '=', True), ('sequence', '>', 1)], context=context)
|
||||
if stage_id:
|
||||
if stages_leads.get(stage_id):
|
||||
stages_leads[stage_id].append(lead.id)
|
||||
@@ -415,7 +415,7 @@ class crm_lead(format_address, osv.osv):
|
||||
"""
|
||||
stages_leads = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 100.0), ('fold', '=', True)], context=context)
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 100.0), ('on_change', '=', True)], context=context)
|
||||
if stage_id:
|
||||
if stages_leads.get(stage_id):
|
||||
stages_leads[stage_id].append(lead.id)
|
||||
@@ -887,6 +887,7 @@ class crm_lead(format_address, osv.osv):
|
||||
(tree_view or False, 'tree'), (False, 'kanban'),
|
||||
(False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {'default_type': 'opportunity'}
|
||||
}
|
||||
|
||||
def redirect_lead_view(self, cr, uid, lead_id, context=None):
|
||||
|
||||
@@ -154,14 +154,106 @@ class account_analytic_line(osv.osv):
|
||||
price = 0.0
|
||||
return price
|
||||
|
||||
def _prepare_cost_invoice(self, cr, uid, partner, company_id, currency_id, analytic_lines, context=None):
|
||||
""" returns values used to create main invoice from analytic lines"""
|
||||
account_payment_term_obj = self.pool['account.payment.term']
|
||||
invoice_name = analytic_lines[0].account_id.name
|
||||
|
||||
date_due = False
|
||||
if partner.property_payment_term:
|
||||
pterm_list = account_payment_term_obj.compute(cr, uid,
|
||||
partner.property_payment_term.id, value=1,
|
||||
date_ref=time.strftime('%Y-%m-%d'))
|
||||
if pterm_list:
|
||||
pterm_list = [line[0] for line in pterm_list]
|
||||
pterm_list.sort()
|
||||
date_due = pterm_list[-1]
|
||||
return {
|
||||
'name': "%s - %s" % (time.strftime('%d/%m/%Y'), invoice_name),
|
||||
'partner_id': partner.id,
|
||||
'company_id': company_id,
|
||||
'payment_term': partner.property_payment_term.id or False,
|
||||
'account_id': partner.property_account_receivable.id,
|
||||
'currency_id': currency_id,
|
||||
'date_due': date_due,
|
||||
'fiscal_position': partner.property_account_position.id
|
||||
}
|
||||
|
||||
def _prepare_cost_invoice_line(self, cr, uid, invoice_id, product_id, uom, user_id,
|
||||
factor_id, account, analytic_lines, 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_lines)
|
||||
total_qty = sum(l.unit_amount for l in analytic_lines)
|
||||
|
||||
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
|
||||
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 or product.categ_id.property_account_income_categ
|
||||
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, taxes)
|
||||
curr_invoice_line.update({
|
||||
'invoice_line_tax_id': [(6, 0, tax)],
|
||||
'name': factor_name,
|
||||
'invoice_line_tax_id': [(6, 0, tax)],
|
||||
'account_id': general_account.id,
|
||||
})
|
||||
|
||||
note = []
|
||||
for line in analytic_lines:
|
||||
# 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):
|
||||
analytic_account_obj = self.pool.get('account.analytic.account')
|
||||
account_payment_term_obj = self.pool.get('account.payment.term')
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
product_obj = self.pool.get('product.product')
|
||||
invoice_factor_obj = self.pool.get('hr_timesheet_invoice.factor')
|
||||
fiscal_pos_obj = self.pool.get('account.fiscal.position')
|
||||
product_uom_obj = self.pool.get('product.uom')
|
||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||
invoices = []
|
||||
if context is None:
|
||||
@@ -169,131 +261,62 @@ class account_analytic_line(osv.osv):
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
journal_types = {}
|
||||
# use key (partner/account, company, currency)
|
||||
# creates one invoice per key
|
||||
invoice_grouping = {}
|
||||
|
||||
currency_id = False
|
||||
# prepare for iteration on journal and accounts
|
||||
for line in self.pool.get('account.analytic.line').browse(cr, uid, ids, context=context):
|
||||
if line.journal_id.type not in journal_types:
|
||||
journal_types[line.journal_id.type] = set()
|
||||
journal_types[line.journal_id.type].add(line.account_id.id)
|
||||
for journal_type, account_ids in journal_types.items():
|
||||
for account in analytic_account_obj.browse(cr, uid, list(account_ids), context=context):
|
||||
partner = account.partner_id
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
|
||||
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_lines in invoice_grouping.items():
|
||||
# key_id is an account.analytic.account
|
||||
partner = analytic_lines[0].account_id.partner_id # will be the same for every line
|
||||
|
||||
curr_invoice = self._prepare_cost_invoice(cr, uid, partner, company_id, currency_id, analytic_lines, 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_lines:
|
||||
account = analytic_line.account_id
|
||||
if (not partner) or not (account.pricelist_id):
|
||||
raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields.'))
|
||||
raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
|
||||
|
||||
date_due = False
|
||||
if partner.property_payment_term:
|
||||
pterm_list= account_payment_term_obj.compute(cr, uid,
|
||||
partner.property_payment_term.id, value=1,
|
||||
date_ref=time.strftime('%Y-%m-%d'))
|
||||
if pterm_list:
|
||||
pterm_list = [line[0] for line in pterm_list]
|
||||
pterm_list.sort()
|
||||
date_due = pterm_list[-1]
|
||||
if not analytic_line.to_invoice:
|
||||
raise UserError(_('Trying to invoice non invoiceable line for %s.') % (analytic_line.product_id.name))
|
||||
|
||||
curr_invoice = {
|
||||
'name': time.strftime('%d/%m/%Y') + ' - '+account.name,
|
||||
'partner_id': account.partner_id.id,
|
||||
'company_id': account.company_id.id,
|
||||
'payment_term': partner.property_payment_term.id or False,
|
||||
'account_id': partner.property_account_receivable.id,
|
||||
'currency_id': account.pricelist_id.currency_id.id,
|
||||
'date_due': date_due,
|
||||
'fiscal_position': account.partner_id.property_account_position.id
|
||||
}
|
||||
context2 = context.copy()
|
||||
context2['lang'] = partner.lang
|
||||
# set company_id in context, so the correct default journal will be selected
|
||||
context2['force_company'] = curr_invoice['company_id']
|
||||
# set force_company in context so the correct product properties are selected (eg. income account)
|
||||
context2['company_id'] = curr_invoice['company_id']
|
||||
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)
|
||||
invoice_lines_grouping.setdefault(key, []).append(analytic_line)
|
||||
|
||||
last_invoice = invoice_obj.create(cr, uid, curr_invoice, context=context2)
|
||||
invoices.append(last_invoice)
|
||||
# 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=context)
|
||||
|
||||
cr.execute("""SELECT product_id, user_id, to_invoice, sum(amount), sum(unit_amount), product_uom_id
|
||||
FROM account_analytic_line as line LEFT JOIN account_analytic_journal journal ON (line.journal_id = journal.id)
|
||||
WHERE account_id = %s
|
||||
AND line.id IN %s AND journal.type = %s AND to_invoice IS NOT NULL
|
||||
GROUP BY product_id, user_id, to_invoice, product_uom_id""", (account.id, tuple(ids), journal_type))
|
||||
|
||||
for product_id, user_id, factor_id, total_price, qty, uom in cr.fetchall():
|
||||
context2.update({'uom': uom})
|
||||
|
||||
if data.get('product'):
|
||||
# force product, use its public price
|
||||
product_id = data['product'][0]
|
||||
unit_price = self._get_invoice_price(cr, uid, account, product_id, user_id, qty, context2)
|
||||
elif journal_type == 'general' and product_id:
|
||||
# timesheets, use sale price
|
||||
unit_price = self._get_invoice_price(cr, uid, account, product_id, user_id, qty, context2)
|
||||
else:
|
||||
# expenses, using price from amount field
|
||||
unit_price = total_price*-1.0 / qty
|
||||
|
||||
factor = invoice_factor_obj.browse(cr, uid, factor_id, context=context2)
|
||||
# factor_name = factor.customer_name and line_name + ' - ' + factor.customer_name or line_name
|
||||
factor_name = factor.customer_name
|
||||
curr_line = {
|
||||
'price_unit': unit_price,
|
||||
'quantity': qty,
|
||||
'product_id': product_id or False,
|
||||
'discount': factor.factor,
|
||||
'invoice_id': last_invoice,
|
||||
'name': factor_name,
|
||||
'uos_id': uom,
|
||||
'account_analytic_id': account.id,
|
||||
}
|
||||
product = product_obj.browse(cr, uid, product_id, context=context2)
|
||||
if product:
|
||||
factor_name = product_obj.name_get(cr, uid, [product_id], context=context2)[0][1]
|
||||
if factor.customer_name:
|
||||
factor_name += ' - ' + factor.customer_name
|
||||
|
||||
general_account = product.property_account_income or product.categ_id.property_account_income_categ
|
||||
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 = fiscal_pos_obj.map_tax(cr, uid, account.partner_id.property_account_position, taxes)
|
||||
curr_line.update({
|
||||
'invoice_line_tax_id': [(6,0,tax )],
|
||||
'name': factor_name,
|
||||
'invoice_line_tax_id': [(6,0,tax)],
|
||||
'account_id': general_account.id,
|
||||
})
|
||||
#
|
||||
# Compute for lines
|
||||
#
|
||||
cr.execute("SELECT * FROM account_analytic_line WHERE account_id = %s and id IN %s AND product_id=%s and to_invoice=%s ORDER BY account_analytic_line.date", (account.id, tuple(ids), product_id, factor_id))
|
||||
|
||||
line_ids = cr.dictfetchall()
|
||||
note = []
|
||||
for line in 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'], product_uom_obj.browse(cr, uid, [line['product_uom_id']],context2)[0].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_line['name'] += "\n" + ("\n".join(map(lambda x: unicode(x) or '',note)))
|
||||
invoice_line_obj.create(cr, uid, curr_line, context=context)
|
||||
cr.execute("update account_analytic_line set invoice_id=%s WHERE account_id = %s and id IN %s", (last_invoice, account.id, tuple(ids)))
|
||||
self.invalidate_cache(cr, uid, ['invoice_id'], ids, context=context)
|
||||
|
||||
invoice_obj.button_reset_taxes(cr, uid, [last_invoice], context)
|
||||
invoice_line_obj.create(cr, uid, curr_invoice_line, context=context)
|
||||
self.write(cr, uid, [l.id for l in analytic_lines], {'invoice_id': last_invoice}, context=context)
|
||||
invoice_obj.button_reset_taxes(cr, uid, [last_invoice], context)
|
||||
return invoices
|
||||
|
||||
|
||||
|
||||
class hr_analytic_timesheet(osv.osv):
|
||||
_inherit = "hr.analytic.timesheet"
|
||||
def on_change_account_id(self, cr, uid, ids, account_id, user_id=False):
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
<field name="product_uom_qty" string="Quantity"/>
|
||||
<field name="product_uom" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="tax_id" domain="[('parent_id', '=', False), ('type_tax_use', '=', 'purchase')]" widget="many2many_tags"/>
|
||||
<field name="to_invoice"/>
|
||||
<field name="price_subtotal"/>
|
||||
</tree>
|
||||
|
||||
@@ -183,15 +183,20 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
|
||||
},
|
||||
},{
|
||||
model: 'account.tax',
|
||||
fields: ['name','amount', 'price_include', 'include_base_amount', 'type'],
|
||||
fields: ['name','amount', 'price_include', 'include_base_amount', 'type', 'child_ids', 'child_depend', 'include_base_amount'],
|
||||
domain: null,
|
||||
loaded: function(self,taxes){
|
||||
self.taxes = taxes;
|
||||
loaded: function(self, taxes){
|
||||
self.taxes = taxes;
|
||||
self.taxes_by_id = {};
|
||||
|
||||
for (var i = 0; i < taxes.length; i++) {
|
||||
self.taxes_by_id[taxes[i].id] = taxes[i];
|
||||
}
|
||||
_.each(taxes, function(tax){
|
||||
self.taxes_by_id[tax.id] = tax;
|
||||
});
|
||||
_.each(self.taxes_by_id, function(tax) {
|
||||
tax.child_taxes = {};
|
||||
_.each(tax.child_ids, function(child_tax_id) {
|
||||
tax.child_taxes[child_tax_id] = self.taxes_by_id[child_tax_id];
|
||||
});
|
||||
});
|
||||
},
|
||||
},{
|
||||
model: 'pos.session',
|
||||
@@ -1089,52 +1094,84 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
|
||||
}
|
||||
return taxes;
|
||||
},
|
||||
get_all_prices: function(){
|
||||
compute_all: function(taxes, price_unit) {
|
||||
var self = this;
|
||||
var res = [];
|
||||
var currency_rounding = this.pos.currency.rounding;
|
||||
var base = this.get_base_price();
|
||||
var totalTax = base;
|
||||
var totalNoTax = base;
|
||||
|
||||
var product = this.get_product();
|
||||
var taxes = this.get_applicable_taxes();
|
||||
var taxtotal = 0;
|
||||
var taxdetail = {};
|
||||
_.each(taxes, function(tax) {
|
||||
var base = price_unit;
|
||||
_(taxes).each(function(tax) {
|
||||
if (tax.price_include) {
|
||||
var tmp;
|
||||
if (tax.type === "percent") {
|
||||
tmp = base - round_pr(base / (1 + tax.amount),currency_rounding);
|
||||
tmp = round_pr(base - round_pr(base / (1 + tax.amount),currency_rounding),currency_rounding);
|
||||
data = {amount:tmp, price_include:true, id: tax.id};
|
||||
res.push(data);
|
||||
} else if (tax.type === "fixed") {
|
||||
tmp = round_pr(tax.amount * self.get_quantity(),currency_rounding);
|
||||
data = {amount:tmp, price_include:true, id: tax.id};
|
||||
res.push(data);
|
||||
} else {
|
||||
throw "This type of tax is not supported by the point of sale: " + tax.type;
|
||||
}
|
||||
tmp = round_pr(tmp,currency_rounding);
|
||||
taxtotal += tmp;
|
||||
totalNoTax -= tmp;
|
||||
taxdetail[tax.id] = tmp;
|
||||
} else {
|
||||
var tmp;
|
||||
if (tax.type === "percent") {
|
||||
tmp = tax.amount * base;
|
||||
tmp = round_pr(tax.amount * base, currency_rounding);
|
||||
data = {amount:tmp, price_include:false, id: tax.id};
|
||||
res.push(data);
|
||||
} else if (tax.type === "fixed") {
|
||||
tmp = tax.amount * self.get_quantity();
|
||||
tmp = round_pr(tax.amount * self.get_quantity(), currency_rounding);
|
||||
data = {amount:tmp, price_include:false, id: tax.id};
|
||||
res.push(data);
|
||||
} else {
|
||||
throw "This type of tax is not supported by the point of sale: " + tax.type;
|
||||
}
|
||||
|
||||
tmp = round_pr(tmp,currency_rounding);
|
||||
|
||||
if (tax.include_base_amount) {
|
||||
base += tmp;
|
||||
var base_amount = data.amount;
|
||||
var child_amount = 0.0;
|
||||
if (tax.child_depend) {
|
||||
res.pop(); // do not use parent tax
|
||||
child_tax = self.compute_all(tax.child_taxes, base_amount);
|
||||
res.push(child_tax);
|
||||
_(child_tax).each(function(child) {
|
||||
child_amount += child.amount;
|
||||
});
|
||||
}
|
||||
if (tax.include_base_amount) {
|
||||
base += base_amount + child_amount;
|
||||
}
|
||||
|
||||
taxtotal += tmp;
|
||||
totalTax += tmp;
|
||||
taxdetail[tax.id] = tmp;
|
||||
}
|
||||
});
|
||||
return res;
|
||||
},
|
||||
get_all_prices: function(){
|
||||
var base = round_pr(this.get_quantity() * this.get_unit_price() * (1.0 - (this.get_discount() / 100.0)), this.pos.currency.rounding);
|
||||
var totalTax = base;
|
||||
var totalNoTax = base;
|
||||
var taxtotal = 0;
|
||||
|
||||
var product = this.get_product();
|
||||
var taxes_ids = product.taxes_id;
|
||||
var taxes = this.pos.taxes;
|
||||
var taxdetail = {};
|
||||
var product_taxes = [];
|
||||
|
||||
_(taxes_ids).each(function(el){
|
||||
product_taxes.push(_.detect(taxes, function(t){
|
||||
return t.id === el;
|
||||
}));
|
||||
});
|
||||
|
||||
var all_taxes = _(this.compute_all(product_taxes, base)).flatten();
|
||||
|
||||
_(all_taxes).each(function(tax) {
|
||||
if (tax.price_include) {
|
||||
totalNoTax -= tax.amount;
|
||||
} else {
|
||||
totalTax += tax.amount;
|
||||
}
|
||||
taxtotal += tax.amount;
|
||||
taxdetail[tax.id] = tax.amount;
|
||||
});
|
||||
|
||||
return {
|
||||
"priceWithTax": totalTax,
|
||||
"priceWithoutTax": totalNoTax,
|
||||
|
||||
@@ -1031,7 +1031,7 @@ class task(osv.osv):
|
||||
def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
if (task.stage_id and task.stage_id.sequence <= 1) or (task.planned_hours == 0.0):
|
||||
self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context)
|
||||
self.write(cr, uid, [task.id], {'planned_hours': remaining_time + task.effective_hours}, context=context)
|
||||
self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context)
|
||||
return True
|
||||
|
||||
|
||||
@@ -861,7 +861,7 @@ class purchase_order(osv.osv):
|
||||
Orders will only be merged if:
|
||||
* Purchase Orders are in draft
|
||||
* Purchase Orders belong to the same partner
|
||||
* Purchase Orders are have same stock location, same pricelist
|
||||
* Purchase Orders are have same stock location, same pricelist, same currency
|
||||
Lines will only be merged if:
|
||||
* Order lines are exactly the same except for the quantity and unit
|
||||
|
||||
@@ -897,12 +897,13 @@ class purchase_order(osv.osv):
|
||||
# Compute what the new orders should contain
|
||||
new_orders = {}
|
||||
|
||||
order_lines_to_move = []
|
||||
order_lines_to_move = {}
|
||||
for porder in [order for order in self.browse(cr, uid, ids, context=context) if order.state == 'draft']:
|
||||
order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id'))
|
||||
order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id', 'currency_id'))
|
||||
new_order = new_orders.setdefault(order_key, ({}, []))
|
||||
new_order[1].append(porder.id)
|
||||
order_infos = new_order[0]
|
||||
order_lines_to_move.setdefault(order_key, [])
|
||||
|
||||
if not order_infos:
|
||||
order_infos.update({
|
||||
@@ -913,6 +914,7 @@ class purchase_order(osv.osv):
|
||||
'picking_type_id': porder.picking_type_id.id,
|
||||
'location_id': porder.location_id.id,
|
||||
'pricelist_id': porder.pricelist_id.id,
|
||||
'currency_id': porder.currency_id.id,
|
||||
'state': 'draft',
|
||||
'order_line': {},
|
||||
'notes': '%s' % (porder.notes or '',),
|
||||
@@ -926,8 +928,7 @@ class purchase_order(osv.osv):
|
||||
if porder.origin:
|
||||
order_infos['origin'] = (order_infos['origin'] or '') + ' ' + porder.origin
|
||||
|
||||
for order_line in porder.order_line:
|
||||
order_lines_to_move += [order_line.id]
|
||||
order_lines_to_move[order_key] += [order_line.id for order_line in porder.order_line]
|
||||
|
||||
allorders = []
|
||||
orders_info = {}
|
||||
@@ -941,7 +942,7 @@ class purchase_order(osv.osv):
|
||||
for key, value in order_data['order_line'].iteritems():
|
||||
del value['uom_factor']
|
||||
value.update(dict(key))
|
||||
order_data['order_line'] = [(6, 0, order_lines_to_move)]
|
||||
order_data['order_line'] = [(6, 0, order_lines_to_move[order_key])]
|
||||
|
||||
# create the new order
|
||||
context.update({'mail_create_nolog': True})
|
||||
|
||||
@@ -13,7 +13,7 @@ Please note that:
|
||||
Orders will only be merged if:
|
||||
* Purchase Orders are in draft
|
||||
* Purchase Orders belong to the same supplier
|
||||
* Purchase Orders are have same stock location, same pricelist
|
||||
* Purchase Orders are have same stock location, same pricelist, same currency
|
||||
Lines will only be merged if:
|
||||
* Order lines are exactly the same except for the product,quantity and unit
|
||||
" colspan="4"/>
|
||||
|
||||
+4
-3
@@ -330,7 +330,8 @@ class sale_order(osv.osv):
|
||||
part = self.pool.get('res.partner').browse(cr, uid, part, context=context)
|
||||
addr = self.pool.get('res.partner').address_get(cr, uid, [part.id], ['delivery', 'invoice', 'contact'])
|
||||
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
|
||||
payment_term = part.property_payment_term and part.property_payment_term.id or False
|
||||
invoice_part = self.pool.get('res.partner').browse(cr, uid, addr['invoice'], context=context)
|
||||
payment_term = invoice_part.property_payment_term and invoice_part.property_payment_term.id or False
|
||||
dedicated_salesman = part.user_id and part.user_id.id or uid
|
||||
val = {
|
||||
'partner_invoice_id': addr['invoice'],
|
||||
@@ -393,14 +394,14 @@ class sale_order(osv.osv):
|
||||
'origin': order.name,
|
||||
'type': 'out_invoice',
|
||||
'reference': order.client_order_ref or order.name,
|
||||
'account_id': order.partner_id.property_account_receivable.id,
|
||||
'account_id': order.partner_invoice_id.property_account_receivable.id,
|
||||
'partner_id': order.partner_invoice_id.id,
|
||||
'journal_id': journal_ids[0],
|
||||
'invoice_line': [(6, 0, lines)],
|
||||
'currency_id': order.pricelist_id.currency_id.id,
|
||||
'comment': order.note,
|
||||
'payment_term': order.payment_term and order.payment_term.id or False,
|
||||
'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
|
||||
'fiscal_position': order.fiscal_position.id or order.partner_invoice_id.property_account_position.id,
|
||||
'date_invoice': context.get('date_invoice', False),
|
||||
'company_id': order.company_id.id,
|
||||
'user_id': order.user_id and order.user_id.id or False,
|
||||
|
||||
@@ -264,12 +264,7 @@
|
||||
Click to add a serial number.
|
||||
</p><p>
|
||||
This is the list of all the production lots you recorded. When
|
||||
you select a lot, you can get the
|
||||
traceability of the products contained in lot. By default, the
|
||||
list is filtered on the serial numbers that are available in
|
||||
your warehouse but you can uncheck the 'Available' button to
|
||||
get all the lots you produced, received or delivered to
|
||||
customers.
|
||||
you select a lot, you can get the traceability of the products contained in lot.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -227,10 +227,6 @@ instance.web.parse_value = function (value, descriptor, value_if_empty) {
|
||||
throw new Error(_.str.sprintf(_t("'%s' is not a correct integer"), value));
|
||||
return tmp;
|
||||
case 'float':
|
||||
tmp = Number(value);
|
||||
if (!isNaN(tmp))
|
||||
return tmp;
|
||||
|
||||
var tmp2 = value;
|
||||
do {
|
||||
tmp = tmp2;
|
||||
|
||||
@@ -11,6 +11,15 @@ instance.web_kanban.SparklineBarWidget = instance.web_kanban.AbstractField.exten
|
||||
var self = this;
|
||||
var title = this.$node.html() || this.field.string;
|
||||
setTimeout(function () {
|
||||
var tooltipFormatter = function(sp, options, fields) {
|
||||
var format = $.spformat('<div class="jqsfield">{{offset:offset}} {{formatted_value}}</div>');
|
||||
var result = '';
|
||||
$.each(fields, function(i, field) {
|
||||
field.formatted_value = instance.web.format_value(field.value, { type : 'float' });
|
||||
result += format.render(field, options.get('tooltipValueLookups'), options);
|
||||
})
|
||||
return result;
|
||||
}
|
||||
var field_value = JSON.parse(self.field.value);
|
||||
var value = _.pluck(field_value, 'value');
|
||||
var tooltips = _.pluck(field_value, 'tooltip');
|
||||
@@ -24,6 +33,7 @@ instance.web_kanban.SparklineBarWidget = instance.web_kanban.AbstractField.exten
|
||||
barSpacing: 1,
|
||||
barColor: '#96d854',
|
||||
tooltipFormat: tooltipFormat,
|
||||
tooltipFormatter: self.options.type == 'tristate' ? undefined : tooltipFormatter,
|
||||
chartRangeMin: 0,
|
||||
tooltipValueLookups: {
|
||||
'offset': tooltips
|
||||
|
||||
@@ -36,7 +36,7 @@ class sale_quote(http.Controller):
|
||||
def view(self, order_id, pdf=None, token=None, message=False, **post):
|
||||
# use SUPERUSER_ID allow to access/view order for public user
|
||||
# only if he knows the private token
|
||||
order = request.registry.get('sale.order').browse(request.cr, token and SUPERUSER_ID or request.uid, order_id)
|
||||
order = request.registry.get('sale.order').browse(request.cr, token and SUPERUSER_ID or request.uid, order_id, request.context)
|
||||
now = time.strftime('%Y-%m-%d')
|
||||
dummy, action = request.registry.get('ir.model.data').get_object_reference(request.cr, request.uid, 'sale', 'action_quotations')
|
||||
if token:
|
||||
|
||||
+1
-1
@@ -4,4 +4,4 @@ Business Mementoes
|
||||
|
||||
.. toctree::
|
||||
|
||||
Accounting Memento <https://odoo.com/documentation/functional/accounting.html>
|
||||
Accounting Memento (US GAAP) <https://odoo.com/documentation/functional/accounting.html>
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
Brazil, France, 2015-04-14
|
||||
|
||||
Akretion France agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Sébastien BEAU sebastien.beau@akretion.com https://github.com/akretion
|
||||
|
||||
|
||||
Akretion LTDA agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
Raphaël Valyi raphael.valyi@akretion.com https://github.com/akretion
|
||||
|
||||
|
||||
List of contributors:
|
||||
|
||||
Abdessamad Hilali abdessamad.hilali@akretion.com https://github.com/ahilali
|
||||
Adrien Chaussende adrien.chaussende@akretion.com https://github.com/achaussende
|
||||
Alexis de Lattre alexis.delattre@akretion.com https://github.com/alexis-via
|
||||
Arthur Vuillard arthur.vuillard@akretion.com https://github.com/arthru
|
||||
Benoît Guillot benoit.guillot@akretion.com https://github.com/bguillot
|
||||
Chafique delli chafique.delli@akretion.com https://github.com/chafique-delli
|
||||
Cilene Oliveira cilene.oliveira@akretion.com https://github.com/cileneoliveira
|
||||
David Beal david.beal@akretion.com https://github.com/bealdav
|
||||
Florian da Costa florian.dacosta@akretion.com https://github.com/florian-dacosta
|
||||
Magno Barcelo da Costa magno.costa@akretion.com.br https://github.com/mbcosta
|
||||
Raphaël Valyi raphael.valyi@akretion.com https://github.com/rvalyi
|
||||
Renato Lima renato.lima@akretion.com https://github.com/renatonlima
|
||||
Sebastien Beau sebastien.beau@akretion.com https://github.com/sebastienbeau
|
||||
Sylvain Calador sylvain.calador@akretion.com https://github.com/sylvainc
|
||||
Sylvain Legal sylvain.legal@akretion.com https://github.com/legalsylvain
|
||||
Thiago Moreira de Souza Arrais thiago.moreira@akretion.com.br https://github.com/thiagomds
|
||||
Valentin Chemiere valentin.chemiere@akretion.com https://github.com/viggor
|
||||
Vianney da Costa vianney.dacosta@akretion.com.br https://launchpad.net/~vianneydc
|
||||
@@ -0,0 +1,11 @@
|
||||
Canada, March 21 2015
|
||||
|
||||
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Jean-Nicolas Brunet jnbrunet2000@gmail.com https://github.com/jnbrunet
|
||||
Reference in New Issue
Block a user