[MERGE] forward port of branch 8.0 up to ea54d4a

This commit is contained in:
Christophe Simonis
2015-01-06 11:49:04 +01:00
161 changed files with 6310 additions and 24900 deletions
+1
View File
@@ -6,5 +6,6 @@ Contributing to Odoo
TL;DR
* Use this [template](https://github.com/odoo/odoo/wiki/Contributing#reporting-issues) when reporting issues, and please search for duplicates first!
* The issues not linked to pull requests will be handled with a low priority.
* Pull requests must be made against the [correct version](https://github.com/odoo/odoo/wiki/Contributing#against-which-version-should-i-submit-a-patch)
* There are restrictions on the kind of [changes allowed in stable series](https://github.com/odoo/odoo/wiki/Contributing#what-does-stable-mean)
+9 -29
View File
@@ -5,43 +5,23 @@ Odoo
Odoo is a suite of web based open source business apps.
The main Odoo Apps include an <a href="https://www.odoo.com/page/crm">Open Source CRM</a>, <a href="https://www.odoo.com/page/website-builder">Website Builder</a>, <a href="https://www.odoo.com/page/e-commerce">eCommerce</a>, <a href="https://www.odoo.com/page/project-management">Project Management</a>, <a href="https://www.odoo.com/page/accounting">Billing & Accounting</a>, <a href="https://www.odoo.com/page/point-of-sale">Point of Sale</a>, <a href="https://www.odoo.com/page/employees">Human Resources</a>, Marketing, Manufacturing, Purchase Management, ...
The main Odoo Apps include an <a href="https://www.odoo.com/page/crm">Open Source CRM</a>, <a href="https://www.odoo.com/page/website-builder">Website Builder</a>, <a href="https://www.odoo.com/page/e-commerce">eCommerce</a>, <a href="https://www.odoo.com/page/project-management">Project Management</a>, <a href="https://www.odoo.com/page/accounting">Billing &amp; Accounting</a>, <a href="https://www.odoo.com/page/point-of-sale">Point of Sale</a>, <a href="https://www.odoo.com/page/employees">Human Resources</a>, Marketing, Manufacturing, Purchase Management, ...
Odoo Apps can be used as stand-alone applications, but they also integrate seamlessly so you get
a full-featured <a href="https://www.odoo.com">Open Source ERP</a> when you install several Apps.
Getting started with Odoo development
--------------------------------------
Getting started with Odoo
-------------------------
If you are a developer type the following command at your terminal:
For a standard installation please follow the <a href="https://www.odoo.com/documentation/8.0/setup/install.html">Setup instructions</a>
from the documentation.
If you are a developer you may type the following command at your terminal:
wget -O- https://raw.githubusercontent.com/odoo/odoo/master/odoo.py | python
Then follow <a href="https://doc.odoo.com/trunk/server/howto/howto_website/">the developer tutorial</a>
Packages, tarballs and installers
---------------------------------
* Debian packages
Add this apt repository to your /etc/apt/sources.list file
deb http://nightly.odoo.com/master/nightly/deb/ ./
Then type:
$ sudo apt-get update
$ sudo apt-get install odoo
If you plan to use Odoo with a local database, please make sure to install PostgreSQL *before* installing the Odoo Debian package.
* <a href="http://nightly.odoo.com/master/nightly/src/">Source tarballs</a>
* <a href="http://nightly.odoo.com/master/nightly/exe/">Windows installer</a>
* <a href="http://nightly.odoo.com/master/nightly/rpm/">RPM package</a>
Then follow <a href="https://www.odoo.com/documentation/8.0/tutorials.html">the developer tutorials</a>
For Odoo employees
+1 -1
View File
@@ -1261,7 +1261,7 @@ class account_invoice_line(models.Model):
uos_id = fields.Many2one('product.uom', string='Unit of Measure',
ondelete='set null', index=True)
product_id = fields.Many2one('product.product', string='Product',
ondelete='set null', index=True)
ondelete='restrict', index=True)
account_id = fields.Many2one('account.account', string='Account',
required=True, domain=[('type', 'not in', ['view', 'closed'])],
default=_default_account,
+18 -21
View File
@@ -1197,7 +1197,7 @@ class account_move_line(osv.osv):
if journal.centralisation:
self._check_moves(cr, uid, context=ctx)
result = super(account_move_line, self).write(cr, uid, ids, vals, context)
if check:
if check and not context.get('novalidate'):
done = []
for line in self.browse(cr, uid, ids):
if line.move_id.id not in done:
@@ -1339,24 +1339,23 @@ class account_move_line(osv.osv):
account_id = 'account_paid_id'
base_sign = 'ref_base_sign'
tax_sign = 'ref_tax_sign'
tmp_cnt = 0
base_adjusted = False
for tax in tax_obj.compute_all(cr, uid, [tax_id], total, 1.00, force_excluded=False).get('taxes'):
#create the base movement
if tmp_cnt == 0:
if tax[base_code]:
tmp_cnt += 1
if tax_id.price_include:
total = tax['price_unit']
newvals = {
'tax_code_id': tax[base_code],
'tax_amount': tax[base_sign] * abs(total),
}
if tax_id.price_include:
if tax['price_unit'] < 0:
newvals['credit'] = abs(tax['price_unit'])
else:
newvals['debit'] = tax['price_unit']
self.write(cr, uid, [result], newvals, context=context)
if base_adjusted == False:
base_adjusted = True
if tax_id.price_include:
total = tax['price_unit']
newvals = {
'tax_code_id': tax[base_code],
'tax_amount': tax[base_sign] * abs(total),
}
if tax_id.price_include:
if tax['price_unit'] < 0:
newvals['credit'] = abs(tax['price_unit'])
else:
newvals['debit'] = tax['price_unit']
self.write(cr, uid, [result], newvals, context=context)
else:
data = {
'move_id': vals['move_id'],
@@ -1372,8 +1371,7 @@ class account_move_line(osv.osv):
'credit': 0.0,
'debit': 0.0,
}
if data['tax_code_id']:
self.create(cr, uid, data, context)
self.create(cr, uid, data, context)
#create the Tax movement
data = {
'move_id': vals['move_id'],
@@ -1389,8 +1387,7 @@ class account_move_line(osv.osv):
'credit': tax['amount']<0 and -tax['amount'] or 0.0,
'debit': tax['amount']>0 and tax['amount'] or 0.0,
}
if data['tax_code_id']:
self.create(cr, uid, data, context)
self.create(cr, uid, data, context)
del vals['account_tax_id']
if check and not context.get('novalidate') and (context.get('recompute', True) or journal.entry_posted):
+16 -6
View File
@@ -625,7 +625,7 @@
<label for="balance_end" />
<button name="button_dummy" states="draft" string="(update)" type="object" class="oe_edit_only oe_link"/>
</div>
<field name="balance_end" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency_id'}"/>
<field name="balance_end" nolabel="1" class="oe_subtotal_footer_separator" widget='monetary' options="{'currency_field': 'currency'}"/>
</group>
<div class="oe_clear"/>
</sheet>
@@ -1097,7 +1097,9 @@
<group>
<field name="name"/>
<field name="ref"/>
<field name="partner_id" on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
</group>
<group>
<field name="journal_id"/>
@@ -1170,7 +1172,9 @@
<field name="journal_id" readonly="False"/>
<field name="period_id" readonly="False"/>
<field name="account_id" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation'),('company_id', '=', company_id)]"/>
<field name="partner_id" on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
on_change="onchange_partner_id(False,partner_id,account_id,debit,credit,date)"/>
<newline/>
<field name="debit"/>
<field name="credit"/>
@@ -1214,7 +1218,9 @@
<field name="name"/>
<field name="ref"/>
<field name="statement_id" invisible="1"/>
<field name="partner_id" on_change="onchange_partner_id(move_id, partner_id, account_id, debit, credit, date, journal_id)"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
on_change="onchange_partner_id(move_id, partner_id, account_id, debit, credit, date, journal_id)"/>
<field name="account_id" options='{"no_open":True}' domain="[('journal_id','=',journal_id), ('company_id', '=', company_id)]" on_change="onchange_account_id(account_id, partner_id, context)"/>
<field name="account_tax_id" options='{"no_open":True}' invisible="context.get('journal_type', False) not in ['sale','sale_refund','purchase','purchase_refund','general']"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting" domain="[('type','not in',['view','template'])]" invisible="not context.get('analytic_journal_id',False)"/>
@@ -1396,7 +1402,9 @@
<group col="6" colspan="4">
<field name="name"/>
<field name="ref"/>
<field name="partner_id" on_change="onchange_partner_id(False, partner_id, account_id, debit, credit, date, journal_id, context)"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
on_change="onchange_partner_id(False, partner_id, account_id, debit, credit, date, journal_id, context)"/>
<field name="journal_id"/>
<field name="period_id"/>
@@ -1460,7 +1468,9 @@
<tree colors="blue:state == 'draft';black:state == 'posted'" editable="top" string="Journal Items">
<field name="invoice"/>
<field name="name"/>
<field name="partner_id" on_change="onchange_partner_id(False, partner_id, account_id, debit, credit, parent.date, parent.journal_id, context)"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
on_change="onchange_partner_id(False, partner_id, account_id, debit, credit, parent.date, parent.journal_id, context)"/>
<field name="account_id" domain="[('journal_id','=',parent.journal_id),('company_id', '=', parent.company_id)]"/>
<field name="date_maturity"/>
<field name="debit" sum="Total Debit"/>
@@ -155,10 +155,10 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
dates_query += ' BETWEEN %s AND %s)'
args_list += (form[str(i)]['start'], form[str(i)]['stop'])
elif form[str(i)]['start']:
dates_query += ' > %s)'
dates_query += ' >= %s)'
args_list += (form[str(i)]['start'],)
else:
dates_query += ' < %s)'
dates_query += ' <= %s)'
args_list += (form[str(i)]['stop'],)
args_list += (self.date_from,)
self.cr.execute('''SELECT l.partner_id, SUM(l.debit-l.credit), l.reconcile_partial_id
@@ -181,11 +181,21 @@ class aged_trial_report(report_sxw.rml_parse, common_report_header):
# in case of partial reconciliation, we want to keep the left amount in the oldest period
self.cr.execute('''SELECT MIN(COALESCE(date_maturity,date)) FROM account_move_line WHERE reconcile_partial_id = %s''', (partner_info[2],))
date = self.cr.fetchall()
if date and args_list[-3] <= date[0][0] <= args_list[-2]:
partial = False
if 'BETWEEN' in dates_query:
partial = date and args_list[-3] <= date[0][0] <= args_list[-2]
elif '>=' in dates_query:
partial = date and date[0][0] >= form[str(i)]['start']
else:
partial = date and date[0][0] <= form[str(i)]['stop']
if partial:
# partial reconcilation
limit_date = 'COALESCE(l.date_maturity,l.date) %s %%s' % '<=' if self.direction_selection == 'past' else '>='
self.cr.execute('''SELECT SUM(l.debit-l.credit)
FROM account_move_line AS l
WHERE l.reconcile_partial_id = %s''', (partner_info[2],))
FROM account_move_line AS l, account_move AS am
WHERE l.move_id = am.id AND am.state in %s
AND l.reconcile_partial_id = %s
AND ''' + limit_date, (tuple(move_state), partner_info[2], self.date_from))
unreconciled_amount = self.cr.fetchall()
partners_amount[partner_info[0]] += unreconciled_amount[0][0]
else:
@@ -115,7 +115,8 @@
groups="group_account_manager"
context="{'search_default_partner_id':[active_id], 'search_default_month':1,'search_default_user':1,'group_by_no_leaf':1,'group_by':[]}"
res_model="account.invoice.report"
src_model="res.partner"/>
src_model="res.partner"
view_mode="graph"/>
</data>
</openerp>
@@ -163,10 +163,6 @@
width: 100%; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr {
cursor: pointer; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.created_line, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.created_line {
cursor: default !important; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.created_line .line_remove_button, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table tr.created_line .line_remove_button {
cursor: pointer; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match table td {
padding: 1px 8px;
vertical-align: middle; }
@@ -225,10 +221,14 @@
padding-bottom: 3px; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption {
text-align: left;
font-size: 1.1em;
font-weight: bold;
height: 26px;
margin: 0 15px 4px 15px; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption .partner_name {
font-size: 1.1em;
font-weight: bold; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption .tip_reconciliation_not_balanced {
float: right;
padding-right: 7px; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption button {
float: right;
position: relative;
@@ -238,8 +238,7 @@
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption > span, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view caption > input {
position: relative;
top: 7px;
/* meh */
font-weight: bold; }
/* meh */ }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td.cell_credit {
border-left: 1px solid #000; }
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls {
@@ -267,14 +267,6 @@ $aestetic_animation_speed: 300ms;
tr {
cursor: pointer;
&.created_line {
cursor: default !important;
.line_remove_button {
cursor: pointer;
}
}
}
td {
@@ -373,11 +365,19 @@ $aestetic_animation_speed: 300ms;
caption {
text-align: left;
font-size: 1.1em;
font-weight: bold;
height: 26px;
margin: 0 $actionColWidth 4px $actionColWidth;
.partner_name {
font-size: 1.1em;
font-weight: bold;
}
.tip_reconciliation_not_balanced {
float: right;
padding-right: 7px;
}
button {
float: right;
position: relative;
@@ -390,7 +390,6 @@ $aestetic_animation_speed: 300ms;
> span, > input {
position: relative; top: 7px; /* meh */
font-weight: bold;
}
}
+53 -51
View File
@@ -1172,7 +1172,7 @@ openerp.account = function (instance) {
var self = this;
$.each(self.$(".tbody_matched_lines .bootstrap_popover"), function(){ $(this).popover('destroy') });
self.$(".tbody_matched_lines").empty();
_(self.get("mv_lines_selected")).each(function(line){
var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: true}));
self.bindPopoverTo($line.find(".line_info_button"));
@@ -1189,7 +1189,7 @@ openerp.account = function (instance) {
_(self.getCreatedLines()).each(function(line){
var $line = $(QWeb.render("bank_statement_reconciliation_created_line", {line: line}));
$line.find(".line_remove_button").click(function(){ self.removeLine($(this).closest(".created_line")) });
$line.click(function(){ self.removeLine($(this)) });
self.$(".tbody_created_lines").append($line);
if (line.no_remove_action) {
// Then the previous line's remove button deletes this line too
@@ -1241,50 +1241,62 @@ openerp.account = function (instance) {
/** Properties changed */
// Updates the validation button and the "open balance" line
// Updates the validation button, the "open balance" line and the partial reconciliation sign
balanceChanged: function() {
var self = this;
var balance = self.get("balance");
// 'reset' the widget to invalid state
self.is_valid = false;
self.$(".tip_reconciliation_not_balanced").show();
self.$(".tbody_open_balance").empty();
// Special case hack : no identified partner
if (self.st_line.has_no_partner) {
if (Math.abs(balance).toFixed(3) === "0.000") {
self.$(".button_ok").addClass("btn-primary");
self.$(".button_ok").removeAttr("disabled");
self.$(".button_ok").text("OK");
self.is_valid = true;
self.$(".button_ok").text("OK").removeClass("btn-primary").attr("disabled", "disabled");
// Find out if the counterpart is lower than, equal or greater than the transaction being reconciled
var balance_type = undefined;
if (Math.abs(self.get("balance")).toFixed(3) === "0.000") balance_type = "equal";
else if (self.get("balance") * self.st_line.amount > 0) balance_type = "greater";
else if (self.get("balance") * self.st_line.amount < 0) balance_type = "lower";
// Adjust to different cases
if (balance_type === "equal") {
displayValidState(true);
} else if (balance_type === "greater") {
createOpenBalance("Create Write-off");
} else if (balance_type === "lower") {
if (self.st_line.has_no_partner) {
createOpenBalance("Choose counterpart");
} else {
self.$(".button_ok").removeClass("btn-primary");
self.$(".button_ok").attr("disabled", "disabled");
self.$(".button_ok").text("OK");
self.is_valid = false;
var debit = (balance > 0 ? self.formatCurrency(balance, self.st_line.currency_id) : "");
var credit = (balance < 0 ? self.formatCurrency(-1*balance, self.st_line.currency_id) : "");
var $line = $(QWeb.render("bank_statement_reconciliation_line_open_balance", {
debit: debit,
credit: credit,
account_code: self.map_account_id_code[self.st_line.open_balance_account_id]
}));
$line.find('.js_open_balance')[0].innerHTML = _t("Choose counterpart");
self.$(".tbody_open_balance").append($line);
displayValidState(false, "Keep open");
createOpenBalance("Open balance");
}
return;
}
if (Math.abs(balance).toFixed(3) === "0.000") {
self.$(".button_ok").addClass("btn-primary");
self.$(".button_ok").text("OK");
} else {
self.$(".button_ok").removeClass("btn-primary");
self.$(".button_ok").text("Keep open");
var debit = (balance > 0 ? self.formatCurrency(balance, self.st_line.currency_id) : "");
var credit = (balance < 0 ? self.formatCurrency(-1*balance, self.st_line.currency_id) : "");
// Show or hide partial reconciliation
if (self.get("mv_lines_selected").length > 0) {
var propose_partial = self.getCreatedLines().length === 0 && self.get("mv_lines_selected").length === 1 && balance_type === "greater" && ! self.get("mv_lines_selected")[0].partial_reconcile;
self.get("mv_lines_selected")[0].propose_partial_reconcile = propose_partial;
self.updateAccountingViewMatchedLines();
}
function displayValidState(higlight_ok_button, ok_button_text) {
self.is_valid = true;
self.$(".tip_reconciliation_not_balanced").hide();
self.$(".button_ok").removeAttr("disabled");
if (higlight_ok_button) self.$(".button_ok").addClass("btn-primary");
if (ok_button_text !== undefined) self.$(".button_ok").text(ok_button_text)
}
function createOpenBalance(name) {
var balance = self.get("balance");
var amount = self.formatCurrency(Math.abs(balance), self.st_line.currency_id);
var $line = $(QWeb.render("bank_statement_reconciliation_line_open_balance", {
debit: debit,
credit: credit,
debit: balance > 0 ? amount : "",
credit: balance < 0 ? amount : "",
account_code: self.map_account_id_code[self.st_line.open_balance_account_id]
}));
self.$(".tbody_open_balance").append($line);
if (name !== undefined)
$line.find(".cell_label").text(name);
self.$(".tbody_open_balance").empty().append($line);
}
},
@@ -1430,6 +1442,8 @@ openerp.account = function (instance) {
line_created_being_edited[index].amount = Math.round(val.amount*rounding)/rounding;
line_created_being_edited[index].amount_str = self.formatCurrency(Math.abs(val.amount), val.currency_id);
}
if (val.amount_with_tax)
line_created_being_edited[index].amount_with_tax = Math.round(val.amount_with_tax*rounding)/rounding;
});
self.set("line_created_being_edited", line_created_being_edited);
self.createdLinesChanged(); // TODO For some reason, previous line doesn't trigger change handler
@@ -1527,20 +1541,8 @@ openerp.account = function (instance) {
});
// Dealing with floating-point
balance = Math.round(balance*1000)/1000;
self.set("balance", balance);
// Propose partial reconciliation if necessary
if (lines_selected_num === 1 &&
self.st_line.amount * balance > 0 &&
self.st_line.amount * (mv_lines_selected[0].debit - mv_lines_selected[0].credit) < 0 &&
! mv_lines_selected[0].partial_reconcile) {
mv_lines_selected[0].propose_partial_reconcile = true;
self.updateAccountingViewMatchedLines();
} else if (lines_selected_num === 1) {
mv_lines_selected[0].propose_partial_reconcile = false;
self.updateAccountingViewMatchedLines();
}
},
// Loads move lines according to the widget's state
@@ -1627,7 +1629,7 @@ openerp.account = function (instance) {
var dict = {};
dict['account_id'] = this.st_line.open_balance_account_id;
dict['name'] = _t("Open balance");
dict['name'] = this.st_line.name + ' : ' + _t("Open balance");
if (balance > 0) dict['debit'] = balance;
if (balance < 0) dict['credit'] = -1*balance;
@@ -64,6 +64,7 @@
<table class="accounting_view">
<caption>
<button class="button_ok btn btn-default btn-sm"></button>
<span class="tip_reconciliation_not_balanced">You must balance the reconciliation</span>
<span t-if="! line.has_no_partner" class="partner_name">
<t t-esc="line.partner_name"/>
<span class="change_partner glyphicon glyphicon-pencil"></span>
@@ -175,7 +176,7 @@
<t t-name="bank_statement_reconciliation_created_line">
<tr class="created_line" t-att-data-lineid="line.id">
<td class="cell_action"><t t-if="! line.no_remove_action"><span class="line_remove_button glyphicon glyphicon-remove"></span></t></td>
<td class="cell_action"><t t-if="! line.no_remove_action"><span class="glyphicon glyphicon-remove"></span></t></td>
<td class="cell_account_code"><t t-esc="line.account_num"/></td>
<td class="cell_due_date"></td>
<td class="cell_label"><t t-esc="line.label"/></td>
@@ -190,7 +191,7 @@
<td class="cell_action"><span class="toggle_create glyphicon glyphicon-play"></span></td>
<td class="cell_account_code"><t t-esc="account_code"/></td>
<td class="cell_due_date"></td>
<td class="cell_label js_open_balance">Open balance</td>
<td class="cell_label">Open balance</td>
<td class="cell_debit"><t t-esc="debit"/></td>
<td class="cell_credit"><t t-esc="credit"/></td>
<td class="cell_info_popover"></td>
+17 -6
View File
@@ -1,4 +1,5 @@
from openerp.tests.common import TransactionCase
import time
class TestReconciliation(TransactionCase):
"""Tests for reconciliation (account.tax)
@@ -36,7 +37,8 @@ class TestReconciliation(TransactionCase):
'currency_id': self.currency_swiss_id,
'name': 'invoice to client',
'account_id': self.account_rcv_id,
'type': 'out_invoice'
'type': 'out_invoice',
'date_invoice': time.strftime('%Y')+'-07-01', # to use USD rate rateUSDbis
})
self.account_invoice_line_model.create(cr, uid, {'product_id': self.product_id,
'quantity': 1,
@@ -49,14 +51,18 @@ class TestReconciliation(TransactionCase):
invoice_record = self.account_invoice_model.browse(cr, uid, [invoice_id])
#we pay half of it on a journal with currency in dollar (bank statement)
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {'journal_id': self.bank_journal_usd_id,})
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {
'journal_id': self.bank_journal_usd_id,
'date': time.strftime('%Y')+'-07-15',
})
bank_stmt_line_id = self.acc_bank_stmt_line_model.create(cr, uid, {'name': 'half payment',
'statement_id': bank_stmt_id,
'partner_id': self.partner_agrolait_id,
'amount': 42,
'amount_currency': 50,
'currency_id': self.currency_swiss_id,})
'currency_id': self.currency_swiss_id,
'date': time.strftime('%Y')+'-07-15',})
#reconcile the payment with the invoice
for l in invoice_record.move_id.line_id:
@@ -103,7 +109,8 @@ class TestReconciliation(TransactionCase):
'currency_id': self.currency_swiss_id,
'name': 'invoice to client',
'account_id': self.account_rcv_id,
'type': 'in_invoice'
'type': 'in_invoice',
'date_invoice': time.strftime('%Y')+'-07-01',
})
self.account_invoice_line_model.create(cr, uid, {'product_id': self.product_id,
'quantity': 1,
@@ -116,14 +123,18 @@ class TestReconciliation(TransactionCase):
invoice_record = self.account_invoice_model.browse(cr, uid, [invoice_id])
#we pay half of it on a journal with currency in dollar (bank statement)
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {'journal_id': self.bank_journal_usd_id,})
bank_stmt_id = self.acc_bank_stmt_model.create(cr, uid, {
'journal_id': self.bank_journal_usd_id,
'date': time.strftime('%Y')+'-07-15',
})
bank_stmt_line_id = self.acc_bank_stmt_line_model.create(cr, uid, {'name': 'half payment',
'statement_id': bank_stmt_id,
'partner_id': self.partner_agrolait_id,
'amount': -42,
'amount_currency': -50,
'currency_id': self.currency_swiss_id,})
'currency_id': self.currency_swiss_id,
'date': time.strftime('%Y')+'-07-15',})
#reconcile the payment with the invoice
for l in invoice_record.move_id.line_id:
+2 -2
View File
@@ -71,7 +71,7 @@
<td class="text-right">
<span t-field="l.price_unit"/>
</td>
<td groups="sale.group_discount_per_so_line"><span t-field="l.discount"/></td>
<td class="text-right" groups="sale.group_discount_per_so_line"><span t-field="l.discount"/></td>
<td>
<span t-esc="', '.join(map(lambda x: x.name, l.invoice_line_tax_id))"/>
</td>
@@ -142,7 +142,7 @@
<p t-if="o.payment_term">
<span t-field="o.payment_term.note"/>
</p>
<p t-if="o.fiscal_position and o.fiscal_position.note">
<p t-if="o.fiscal_position.note">
<strong>Fiscal Position Remark:</strong>
<span t-field="o.fiscal_position.note"/>
</p>
+1 -1
View File
@@ -51,7 +51,7 @@ class account_chart(osv.osv_memory):
FROM account_period p
LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
WHERE f.id = %s
ORDER BY p.date_start ASC
ORDER BY p.date_start ASC, p.special DESC
LIMIT 1) AS period_start
UNION ALL
SELECT * FROM (SELECT p.id
@@ -80,7 +80,7 @@
<button name="%(action_sales_order)d" string="Sales Orders"
type="action"
class="oe_link"
context="{'default_partner_id': [partner_id], 'search_default_project_id': [active_id],'default_project_id': [active_id]}"
context="{'default_partner_id': [partner_id], 'search_default_project_id': [active_id],'default_project_id': [active_id], 'default_pricelist_id': pricelist_id}"
/>
</td>
</tr><tr>
@@ -198,6 +198,7 @@
<field name="name">account.analytic.account.list.contract</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_list"/>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/>
<field name="arch" type="xml">
<field name="date_start" position="before">
<field name="last_invoice_date"/>
@@ -442,7 +442,9 @@ class sale_order_line(osv.osv):
if ids:
sale_line = self.browse(cr, uid, ids[0], context=context)
for line in inv_line_obj.browse(cr, uid, create_ids, context=context):
rec = acct_anal_def_obj.account_get(cr, uid, line.product_id.id, sale_line.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'), context)
rec = acct_anal_def_obj.account_get(cr, uid, line.product_id.id,
sale_line.order_id.partner_id.id, uid, time.strftime('%Y-%m-%d'),
sale_line.order_id.company_id.id, context=context)
if rec:
inv_line_obj.write(cr, uid, [line.id], {'analytics_id': rec.analytics_id.id}, context=context)
+4 -9
View File
@@ -50,14 +50,9 @@ class account_invoice_line(osv.osv):
return res
if type in ('in_invoice','in_refund'):
product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
if type == 'in_invoice':
oa = product_obj.property_stock_account_input and product_obj.property_stock_account_input.id
if not oa:
oa = product_obj.categ_id.property_stock_account_input_categ and product_obj.categ_id.property_stock_account_input_categ.id
else:
oa = product_obj.property_stock_account_output and product_obj.property_stock_account_output.id
if not oa:
oa = product_obj.categ_id.property_stock_account_output_categ and product_obj.categ_id.property_stock_account_output_categ.id
oa = product_obj.property_stock_account_input and product_obj.property_stock_account_input.id
if not oa:
oa = product_obj.categ_id.property_stock_account_input_categ and product_obj.categ_id.property_stock_account_input_categ.id
if oa:
fpos = fposition_id and fiscal_pool.browse(cr, uid, fposition_id, context=context) or False
a = fiscal_pool.map_account(cr, uid, fpos, oa)
@@ -82,7 +77,7 @@ class account_invoice_line(osv.osv):
inv = i_line.invoice_id
company_currency = inv.company_id.currency_id.id
if i_line.product_id and i_line.product_id.valuation == 'real_time':
if i_line.product_id.type != 'service' and i_line.product_id.valuation == 'real_time':
# debit account dacc will be the output account
# first check the product, if empty check the category
dacc = i_line.product_id.property_stock_account_output and i_line.product_id.property_stock_account_output.id
+17 -26
View File
@@ -21,42 +21,33 @@
from openerp.osv import osv
#----------------------------------------------------------
# Stock Picking
#----------------------------------------------------------
class stock_move(osv.Model):
_inherit = "stock.move"
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
""" Add a reference to the stock.move in the invoice line
In anglo-saxon the price for COGS should be taken from stock.move
if possible (fallback on standard_price)
"""
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
res.update({
'move_id': move.id,
})
return res
class stock_picking(osv.osv):
_inherit = "stock.picking"
_description = "Picking List"
def _prepare_invoice_line(self, cr, uid, group, picking, move_line, invoice_id,
invoice_vals, context=None):
"""Overwrite to add move_id reference"""
res = super(stock_picking, self)._prepare_invoice_line(cr, uid, group, picking, move_line, invoice_id, invoice_vals, context=context)
res.update({
'move_id': move_line.id,
})
return res
def action_invoice_create(self, cr, uid, ids, journal_id=False,
group=False, type='out_invoice', context=None):
'''Return ids of created invoices for the pickings'''
res = super(stock_picking,self).action_invoice_create(cr, uid, ids, journal_id, group, type, context=context)
if type == 'in_refund':
if type in ('in_invoice', 'in_refund'):
for inv in self.pool.get('account.invoice').browse(cr, uid, res, context=context):
for ol in inv.invoice_line:
if ol.product_id:
oa = ol.product_id.property_stock_account_output and ol.product_id.property_stock_account_output.id
if not oa:
oa = ol.product_id.categ_id.property_stock_account_output_categ and ol.product_id.categ_id.property_stock_account_output_categ.id
if oa:
fpos = ol.invoice_id.fiscal_position or False
a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a})
elif type == 'in_invoice':
for inv in self.pool.get('account.invoice').browse(cr, uid, res, context=context):
for ol in inv.invoice_line:
if ol.product_id:
if ol.product_id.type != 'service':
oa = ol.product_id.property_stock_account_input and ol.product_id.property_stock_account_input.id
if not oa:
oa = ol.product_id.categ_id.property_stock_account_input_categ and ol.product_id.categ_id.property_stock_account_input_categ.id
@@ -12,14 +12,14 @@
<field name="amount" position="after">
<newline/>
<field name="allow_check" invisible="1"/>
<field name="amount_in_word" attrs="{'invisible':[('allow_check','!=',1)]}" nolabel="1" colspan="6"/>
<field name="amount_in_word" attrs="{'invisible':[('allow_check','!=',True)]}" nolabel="1" colspan="6"/>
<newline/>
</field>
<field name="number" position="replace">
<field name="number" attrs="{'readonly':[('allow_check','!=',1)]}" />
<field name="number" attrs="{'readonly':[('allow_check','!=',True)]}" />
</field>
<button name="proforma_voucher" position="after">
<button name="print_check" icon="gtk-print" string="Print Check" type="object" attrs="{'invisible':['|',('allow_check','!=',1),('state','!=','posted') ]}" class="oe_highlight"/>
<button name="print_check" icon="gtk-print" string="Print Check" type="object" attrs="{'invisible':['|',('allow_check','!=',True),('state','!=','posted') ]}" class="oe_highlight"/>
</button>
</field>
</record>
+1
View File
@@ -24,6 +24,7 @@ _logger = logging.getLogger(__name__)
def fragment_to_query_string(func):
@functools.wraps(func)
def wrapper(self, *a, **kw):
kw.pop('debug', False)
if not kw:
return """<html><head><script>
var l = window.location;
@@ -64,8 +64,8 @@ class res_partner(osv.osv):
_inherit = "res.partner"
_columns = {
'partner_latitude': fields.float('Geo Latitude'),
'partner_longitude': fields.float('Geo Longitude'),
'partner_latitude': fields.float('Geo Latitude', digits=(16, 5)),
'partner_longitude': fields.float('Geo Longitude', digits=(16, 5)),
'date_localization': fields.date('Geo Localization Date'),
}
+15 -15
View File
@@ -32,7 +32,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False):
@param with_date: if a value is passed to this param it will return dates based on value of withdate + calendar_id
@return: real event id
"""
if calendar_id and isinstance(calendar_id, (str, unicode)):
if calendar_id and isinstance(calendar_id, (basestring)):
res = calendar_id.split('-')
if len(res) >= 2:
real_id = res[0]
@@ -46,7 +46,7 @@ def calendar_id2real_id(calendar_id=None, with_date=False):
def get_real_ids(ids):
if isinstance(ids, (str, int, long)):
if isinstance(ids, (basestring, int, long)):
return calendar_id2real_id(ids)
if isinstance(ids, (list, tuple)):
@@ -625,14 +625,14 @@ class ir_model(osv.Model):
_inherit = 'ir.model'
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
new_ids = isinstance(ids, (str, int, long)) and [ids] or ids
new_ids = isinstance(ids, (basestring, int, long)) and [ids] or ids
if context is None:
context = {}
data = super(ir_model, self).read(cr, uid, new_ids, fields=fields, context=context, load=load)
if data:
for val in data:
val['id'] = calendar_id2real_id(val['id'])
return isinstance(ids, (str, int, long)) and data[0] or data
return isinstance(ids, (basestring, int, long)) and data[0] or data
original_exp_report = openerp.service.report.exp_report
@@ -1138,7 +1138,7 @@ class calendar_event(osv.Model):
if not context:
context = {}
if isinstance(event_id, (str, int, long)):
if isinstance(event_id, (basestring, int, long)):
ids_to_browse = [event_id] # keep select for return
else:
ids_to_browse = event_id
@@ -1220,7 +1220,7 @@ class calendar_event(osv.Model):
comparers = [((itemgetter(col[1:]), -1) if col[0] == '-' else (itemgetter(col), 1)) for col in sort_params]
ids = [r['id'] for r in sorted(result_data, cmp=comparer)]
if isinstance(event_id, (str, int, long)):
if isinstance(event_id, (basestring, int, long)):
return ids and ids[0] or False
else:
return ids
@@ -1383,7 +1383,7 @@ class calendar_event(osv.Model):
@api.cr_uid_ids_context
def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
if isinstance(thread_id, str):
if isinstance(thread_id, basestring):
thread_id = get_real_ids(thread_id)
if context.get('default_date'):
del context['default_date']
@@ -1509,7 +1509,7 @@ class calendar_event(osv.Model):
for arg in args:
if arg[0] == 'id':
for n, calendar_id in enumerate(arg[2]):
if isinstance(calendar_id, str):
if isinstance(calendar_id, basestring):
arg[2][n] = calendar_id.split('-')[0]
return super(calendar_event, self)._name_search(cr, user, name=name, args=args, operator=operator, context=context, limit=limit, name_get_uid=name_get_uid)
@@ -1528,7 +1528,7 @@ class calendar_event(osv.Model):
self._set_date(cr, uid, values, id=ids[0], context=context)
for one_ids in ids:
if isinstance(one_ids, (str, int, long)):
if isinstance(one_ids, (basestring, int, long)):
if len(str(one_ids).split('-')) == 1:
ids = [int(one_ids)]
else:
@@ -1624,7 +1624,7 @@ class calendar_event(osv.Model):
for f in EXTRAFIELDS:
if fields and (f not in fields):
fields2.append(f)
if isinstance(ids, (str, int, long)):
if isinstance(ids, (basestring, int, long)):
select = [ids]
else:
select = ids
@@ -1636,7 +1636,7 @@ class calendar_event(osv.Model):
for calendar_id, real_id in select:
res = real_data[real_id].copy()
ls = calendar_id2real_id(calendar_id, with_date=res and res.get('duration', 0) > 0 and res.get('duration') or 1)
if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
if not isinstance(ls, (basestring, int, long)) and len(ls) >= 2:
res['start'] = ls[1]
res['stop'] = ls[2]
@@ -1672,7 +1672,7 @@ class calendar_event(osv.Model):
for k in EXTRAFIELDS:
if (k in r) and (fields and (k not in fields)):
del r[k]
if isinstance(ids, (str, int, long)):
if isinstance(ids, (basestring, int, long)):
return result and result[0] or False
return result
@@ -1711,7 +1711,7 @@ class mail_message(osv.Model):
convert the search on real ids in the case it was asked on virtual ids, then call super()
'''
for index in range(len(args)):
if args[index][0] == "res_id" and isinstance(args[index][2], str):
if args[index][0] == "res_id" and isinstance(args[index][2], basestring):
args[index][2] = get_real_ids(args[index][2])
return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
@@ -1733,7 +1733,7 @@ class ir_attachment(osv.Model):
convert the search on real ids in the case it was asked on virtual ids, then call super()
'''
for index in range(len(args)):
if args[index][0] == "res_id" and isinstance(args[index][2], str):
if args[index][0] == "res_id" and isinstance(args[index][2], basestring):
args[index][2] = get_real_ids(args[index][2])
return super(ir_attachment, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count)
@@ -1741,7 +1741,7 @@ class ir_attachment(osv.Model):
'''
when posting an attachment (new or not), convert the virtual ids in real ids.
'''
if isinstance(vals.get('res_id'), str):
if isinstance(vals.get('res_id'), basestring):
vals['res_id'] = get_real_ids(vals.get('res_id'))
return super(ir_attachment, self).write(cr, uid, ids, vals, context=context)
+1 -1
View File
@@ -326,7 +326,7 @@ class crm_lead(format_address, osv.osv):
""" When changing the user, also set a team_id or restrict team id
to the ones user_id is member of. """
team_id = self._get_default_team_id(cr, uid, context=context)
if user_id and not team_id:
if user_id and not team_id and self.pool['res.users'].has_group(cr, uid, 'base.group_multi_salesteams'):
team_ids = self.pool.get('crm.team').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
if team_ids:
team_id = team_ids[0]
+2 -1
View File
@@ -30,8 +30,9 @@ class res_partner(osv.osv):
# the user may not have access rights for opportunities or meetings
try:
for partner in self.browse(cr, uid, ids, context):
opp_ids = self.pool['crm.lead'].search(cr, uid, [('partner_id', '=', partner.id), ('type', '=', 'opportunity'), ('probability', '<', '100')], context=context)
res[partner.id] = {
'opportunity_count': len(partner.opportunity_ids),
'opportunity_count': len(opp_ids),
'meeting_count': len(partner.meeting_ids),
}
except:
@@ -85,8 +85,8 @@ class res_partner(osv.osv):
class crm_lead(osv.osv):
_inherit = "crm.lead"
_columns = {
'partner_latitude': fields.float('Geo Latitude'),
'partner_longitude': fields.float('Geo Longitude'),
'partner_latitude': fields.float('Geo Latitude', digits=(16, 5)),
'partner_longitude': fields.float('Geo Longitude', digits=(16, 5)),
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner',track_visibility='onchange' , help="Partner this case has been forwarded/assigned to.", select=True),
'date_assign': fields.date('Assignation Date', help="Last date this case was forwarded/assigned to a partner"),
}
@@ -112,6 +112,7 @@
<separator string="Partner Activation" colspan="2"/>
<field name="grade_id" widget="selection"/>
<field name="activation" widget="selection"/>
<field name="assigned_partner_id"/>
<field name="partner_weight"/>
</group>
<group>
+9 -7
View File
@@ -237,9 +237,9 @@
<div>
<field name="weight" class="oe_inline"/>
<field name="weight_uom_id" nolabel="1" class="oe_inline"/>
<field name="number_of_packages"/>
</div>
<field name="weight_net" groups="base.group_no_one"/>
<field name="number_of_packages"/>
</group>
</group>
</xpath>
@@ -276,12 +276,14 @@
<field name="inherit_id" ref="stock.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='main_grp']" position="inside">
<label for="weight" string="Weight"/>
<div>
<field name="weight" class="oe_inline"/>
<field name="weight_uom_id" nolabel="1" class="oe_inline"/>
</div>
<field name="weight_net" groups="base.group_no_one" class="oe_inline"/>
<group>
<label for="weight"/>
<div>
<field name="weight" nolabel="1" class="oe_inline"/>
<field name="weight_uom_id" nolabel="1" class="oe_inline"/>
</div>
<field name="weight_net" groups="base.group_no_one"/>
</group>
</xpath>
</field>
</record>
+1 -1
View File
@@ -88,4 +88,4 @@ class sale_order(osv.Model):
'price_unit': grid_obj.get_price(cr, uid, grid.id, order, time.strftime('%Y-%m-%d'), context),
'tax_id': [(6, 0, taxes_ids)],
'is_delivery': True
})
}, context=context)
+5 -6
View File
@@ -471,11 +471,14 @@ class email_template(osv.osv):
results = dict()
for template, template_res_ids in templates_to_res_ids.iteritems():
# generate fields value for all res_ids linked to the current template
ctx = context.copy()
if template.lang:
ctx['lang'] = template._context.get('lang')
for field in fields:
generated_field_values = self.render_template_batch(
cr, uid, getattr(template, field), template.model, template_res_ids,
post_process=(field == 'body_html'),
context=context)
context=ctx)
for res_id, field_value in generated_field_values.iteritems():
results.setdefault(res_id, dict())[field] = field_value
# compute recipients
@@ -503,13 +506,9 @@ class email_template(osv.osv):
if template.report_template:
for res_id in template_res_ids:
attachments = []
report_name = self.render_template(cr, uid, template.report_name, template.model, res_id, context=context)
report_name = self.render_template(cr, uid, template.report_name, template.model, res_id, context=ctx)
report = report_xml_pool.browse(cr, uid, template.report_template.id, context)
report_service = report.report_name
# Ensure report is rendered using template's language
ctx = context.copy()
if template.lang:
ctx['lang'] = self.render_template_batch(cr, uid, template.lang, template.model, [res_id], context)[res_id] # take 0 ?
if report.report_type in ['qweb-html', 'qweb-pdf']:
result, format = self.pool['report'].get_pdf(cr, uid, [res_id], report_service, context=ctx), 'pdf'
@@ -129,7 +129,7 @@ class mail_compose_message(osv.TransientModel):
email_template = self.pool.get('email.template')
ir_model_pool = self.pool.get('ir.model')
for record in self.browse(cr, uid, ids, context=context):
model_ids = ir_model_pool.search(cr, uid, [('model', '=', record.model)], context=context)
model_ids = ir_model_pool.search(cr, uid, [('model', '=', record.model or 'mail.message')], context=context)
model_id = model_ids and model_ids[0] or False
model_name = ''
if model_id:
+1 -1
View File
@@ -41,7 +41,7 @@
<field name="name">Goal Form</field>
<field name="model">gamification.goal</field>
<field name="arch" type="xml">
<form string="Goal">
<form string="Goal" create="false">
<header>
<button string="Start goal" type="object" name="action_start" states="draft" class="oe_highlight"/>
+6 -3
View File
@@ -624,6 +624,8 @@ class google_calendar(osv.AbstractModel):
new_google_internal_event_id = False
source_event_record = ev_obj.browse(cr, uid, att.event_id.recurrent_id, context)
source_attendee_record_id = att_obj.search(cr, uid, [('partner_id', '=', myPartnerID), ('event_id', '=', source_event_record.id)], context=context)
if not source_attendee_record_id:
continue
source_attendee_record = att_obj.browse(cr, uid, source_attendee_record_id, context)[0]
if att.event_id.recurrent_id_date and source_event_record.allday and source_attendee_record.google_internal_event_id:
@@ -665,9 +667,9 @@ class google_calendar(osv.AbstractModel):
registry = openerp.modules.registry.RegistryManager.get(request.session.db)
with registry.cursor() as cur:
self.pool['res.users'].write(cur, uid, [uid], {'google_calendar_last_sync_date': False}, context=context)
error_key = simplejson.loads(e.read())
error_key = simplejson.loads(str(e))
error_key = error_key.get('error', {}).get('message', 'nc')
error_msg = "Google are lost... the next synchro will be a full synchro. \n\n %s" % error_key
error_msg = "Google is lost... the next synchro will be a full synchro. \n\n %s" % error_key
raise self.pool.get('res.config.settings').get_config_warning(cr, _(error_msg), context=context)
my_google_att_ids = att_obj.search(cr, uid, [
@@ -818,7 +820,8 @@ class google_calendar(osv.AbstractModel):
res = self.update_from_google(cr, uid, parent_event, event.GG.event, "copy", context)
else:
parent_oe_id = event_to_synchronize[base_event][0][1].OE.event_id
calendar_event.unlink(cr, uid, "%s-%s" % (parent_oe_id, new_google_event_id), can_be_deleted=True, context=context)
if parent_oe_id:
calendar_event.unlink(cr, uid, "%s-%s" % (parent_oe_id, new_google_event_id), can_be_deleted=True, context=context)
elif isinstance(actToDo, Delete):
if actSrc == 'GG':
+2 -2
View File
@@ -13,8 +13,8 @@ class calendar_config_settings(osv.TransientModel):
def set_calset(self,cr,uid,ids,context=None) :
params = self.pool['ir.config_parameter']
myself = self.browse(cr,uid,ids[0],context=context)
params.set_param(cr, uid, 'google_calendar_client_id', myself.cal_client_id or '', groups=['base.group_system'], context=None)
params.set_param(cr, uid, 'google_calendar_client_secret', myself.cal_client_secret or '', groups=['base.group_system'], context=None)
params.set_param(cr, uid, 'google_calendar_client_id', myself.cal_client_id.strip() or '', groups=['base.group_system'], context=None)
params.set_param(cr, uid, 'google_calendar_client_secret', myself.cal_client_secret.strip() or '', groups=['base.group_system'], context=None)
def get_default_all(self,cr,uid,ids,context=None):
+1 -1
View File
@@ -59,7 +59,7 @@
<group expand="0" string="Group By">
<filter name="employee" string="Employee" context="{'group_by':'employee_id'}"/>
<separator/>
<filter name="name" string="Month" context="{'group_by':'name'}"/>
<filter name="groupby_name" string="Month" context="{'group_by':'name'}"/>
</group>
</search>
</field>
+6 -2
View File
@@ -316,9 +316,13 @@ class hr_applicant(osv.Model):
return {'value': {'department_id': department_id, 'user_id': user_id}}
def onchange_department_id(self, cr, uid, ids, department_id=False, stage_id=False, context=None):
values = {}
if not stage_id:
stage_id = self.stage_find(cr, uid, [], department_id, [('fold', '=', False)], context=context)
return {'value': {'stage_id': stage_id}}
values['stage_id'] = self.stage_find(cr, uid, [], department_id, [('fold', '=', False)], context=context)
if department_id:
department = self.pool['hr.department'].browse(cr, uid, department_id, context=context)
values['company_id'] = department.company_id.id
return {'value': values}
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
data = {'partner_phone': False,
@@ -39,7 +39,7 @@ class hr_timesheet_report(osv.osv):
def _from(self):
from_str = """
account_analytic_line as aal
left join hr_analytic_timesheet as hat ON (hat.line_id=aal.id)
inner join hr_analytic_timesheet as hat ON (hat.line_id=aal.id)
"""
return from_str
+16 -1
View File
@@ -93,29 +93,41 @@ class StyleStack:
'left': TXT_ALIGN_LT,
'right': TXT_ALIGN_RT,
'center': TXT_ALIGN_CT,
'_order': 1,
},
'underline': {
'off': TXT_UNDERL_OFF,
'on': TXT_UNDERL_ON,
'double': TXT_UNDERL2_ON,
# must be issued after 'size' command
# because ESC ! resets ESC -
'_order': 10,
},
'bold': {
'off': TXT_BOLD_OFF,
'on': TXT_BOLD_ON,
# must be issued after 'size' command
# because ESC ! resets ESC E
'_order': 10,
},
'font': {
'a': TXT_FONT_A,
'b': TXT_FONT_B,
# must be issued after 'size' command
# because ESC ! resets ESC M
'_order': 10,
},
'size': {
'normal': TXT_NORMAL,
'double-height': TXT_2HEIGHT,
'double-width': TXT_2WIDTH,
'double': TXT_DOUBLE,
'_order': 1,
},
'color': {
'black': TXT_COLOR_BLACK,
'red': TXT_COLOR_RED,
'_order': 1,
},
}
@@ -169,7 +181,10 @@ class StyleStack:
def to_escpos(self):
""" converts the current style to an escpos command string """
cmd = ''
for style in self.cmds:
# Sort commands because some commands affect others (see _order attributes above)
ordered_cmds = self.cmds.keys()
ordered_cmds.sort(lambda x, y: cmp(self.cmds[x]['_order'], self.cmds[y]['_order']))
for style in ordered_cmds:
cmd += self.cmds[style][self.get(style)]
return cmd
+31 -21
View File
@@ -26,39 +26,49 @@
'description': """
Swiss localization
==================
**Multilang swiss STERCHI account chart and taxes**
**Author:** Camptocamp SA
**Financial contributors:** Prisme Solutions Informatique SA, Quod SA
**Multilang Swiss PME/KMU 2015 account chart and taxes**
**Translation contributors:** brain-tec AG, Agile Business Group
**Author:** Camptocamp SA
**This release will introduce major changes to l10n_ch.**
**Financial contributors:** Prisme Solutions Informatique SA, Quod SA
Due to important refactoring needs and the Switzerland adoption of new international payment standard during 2013-2014. We have reorganised the swiss localization addons this way:
**Translation contributors:** brain-tec AG, Agile Business Group
- **l10n_ch**: Multilang swiss STERCHI account chart and taxes (official addon)
- **l10n_ch_base_bank**: Technical module that introduces a new and simplified version of bank type management
- **l10n_ch_bank**: List of swiss banks
- **l10n_ch_zip**: List of swiss postal zip
- **l10n_ch_dta**: Support of dta payment protocol (will be deprecated end 2014)
- **l10n_ch_payment_slip**: Support of ESR/BVR payment slip report and reconciliation. Report refactored with easy element positioning.
- **l10n_ch_sepa**: Alpha implementation of PostFinance SEPA/PAIN support will be completed during 2013/2014
The swiss localization addons are organized this way:
The modules will be soon available on OpenERP swiss localization on launchpad:
https://launchpad.net/openerp-swiss-localization
``l10n_ch``
Multilang Swiss PME/KMU 2015 account chart and taxes (official addon)
``l10n_ch_base_bank``
Technical module that introduces a new and simplified version of bank
type management
``l10n_ch_bank``
List of swiss banks
``l10n_ch_zip``
List of swiss postal zip
``l10n_ch_dta``
Support of the DTA payment protocol (will be deprecated by the end of 2014)
``l10n_ch_payment_slip``
Support of ESR/BVR payment slip report and reconciliation.
``l10n_ch`` is located in the core Odoo modules. The other modules are in:
https://github.com/OCA/l10n-switzerland
""",
'version': '7.0',
'version': '8.0',
'author': 'Camptocamp',
'category': 'Localization/Account Charts',
'website': 'http://www.camptocamp.com',
'depends': ['account', 'l10n_multilang'],
'data': ['sterchi_chart/account.xml',
'sterchi_chart/vat2011.xml',
'sterchi_chart/fiscal_position.xml' ],
'data': ['report/balance_sheet.xml',
'report/profit_and_loss.xml',
'chart/account.xml',
'chart/vat2011.xml',
'chart/fiscal_position.xml',
],
'demo': [],
'test': [],
'auto_install': False,
'installable': True,
'images': ['images/config_chart_l10n_ch.jpeg','images/l10n_ch_chart.jpeg']
}
'images': ['images/config_chart_l10n_ch.jpeg', 'images/l10n_ch_chart.jpeg']
}
File diff suppressed because it is too large Load Diff
@@ -148,8 +148,8 @@
<field name="ref_base_sign" eval="-1.0"/>
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="account_collected_id" ref="ch_1170"/>
<field name="account_paid_id" ref="ch_1170"/>
<field name="account_collected_id" ref="ch_coa_2200"/>
<field name="account_paid_id" ref="ch_coa_2200"/>
<field name="type_tax_use">sale</field>
</record>
<record model="account.tax.template" id="vat_25_purchase">
@@ -169,8 +169,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1170"/>
<field name="account_paid_id" ref="ch_coa_1170"/>
</record>
<record model="account.tax.template" id="vat_25_invest">
<field name="name">TVA 2.5% sur invest. et autres ch. (TR)</field>
@@ -189,8 +189,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1171"/>
<field name="account_paid_id" ref="ch_coa_1171"/>
</record>
<record model="account.tax.template" id="vat_38">
@@ -210,8 +210,8 @@
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="ch_1170"/>
<field name="account_paid_id" ref="ch_1170"/>
<field name="account_collected_id" ref="ch_coa_2200"/>
<field name="account_paid_id" ref="ch_coa_2200"/>
</record>
<record model="account.tax.template" id="vat_38_purchase">
<field name="name">TVA 3.8% sur achat B&amp;S (TS)</field>
@@ -230,8 +230,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1170"/>
<field name="account_paid_id" ref="ch_coa_1170"/>
</record>
<record model="account.tax.template" id="vat_38_invest">
<field name="name">TVA 3.8% sur invest. et autres ch. (TS)</field>
@@ -250,8 +250,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1171"/>
<field name="account_paid_id" ref="ch_coa_1171"/>
</record>
<record model="account.tax.template" id="vat_80">
<field name="name">TVA due a 8.0% (TN)</field>
@@ -271,8 +271,8 @@
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="ch_1170"/>
<field name="account_paid_id" ref="ch_1170"/>
<field name="account_collected_id" ref="ch_coa_2200"/>
<field name="account_paid_id" ref="ch_coa_2200"/>
</record>
<record model="account.tax.template" id="vat_80_purchase">
<field name="name">TVA 8.0% sur achat B&amp;S (TN)</field>
@@ -292,8 +292,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1170"/>
<field name="account_paid_id" ref="ch_coa_1170"/>
</record>
<record model="account.tax.template" id="vat_80_invest">
<field name="name">TVA 8.0% sur invest. et autres ch. (TN)</field>
@@ -312,8 +312,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1171"/>
<field name="account_paid_id" ref="ch_coa_1171"/>
</record>
<record model="account.tax.template" id="vat_XO">
<field name="name">TVA due a 0% (Exportations)</field>
@@ -330,8 +330,8 @@
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="ch_1170"/>
<field name="account_paid_id" ref="ch_1170"/>
<field name="account_collected_id" ref="ch_coa_2200"/>
<field name="account_paid_id" ref="ch_coa_2200"/>
</record>
<record model="account.tax.template" id="vat_O_exclude">
<field name="name">TVA 0% exclue</field>
@@ -348,8 +348,8 @@
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">sale</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_2200"/>
<field name="account_paid_id" ref="ch_coa_2200"/>
</record>
<record model="account.tax.template" id="vat_O_import">
<field name="name">TVA 0% Importations de biens et services</field>
@@ -366,8 +366,8 @@
<field name="ref_tax_sign" eval="1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1171"/>
<field name="account_paid_id" ref="ch_coa_1171"/>
</record>
<!--# 100% on import !! the tax percentage is 00-->
<record model="account.tax.template" id="vat_100_import">
@@ -383,8 +383,8 @@
<field name="ref_tax_sign" eval="-1.0"/>
<field name="chart_template_id" ref="l10nch_chart_template"/>
<field name="type_tax_use">purchase</field>
<field name="account_collected_id" ref="ch_1171"/>
<field name="account_paid_id" ref="ch_1171"/>
<field name="account_collected_id" ref="ch_coa_1171"/>
<field name="account_paid_id" ref="ch_coa_1171"/>
</record>
</data>
</openerp>
+996 -6123
View File
File diff suppressed because it is too large Load Diff
+998 -6123
View File
File diff suppressed because it is too large Load Diff
+246
View File
@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data noupdate="1">
<record id="financial_report_9" model="account.financial.report">
<field name="name">BILAN</field>
<field name="sequence">10</field>
<field name="sign" eval="1"/>
<field name="display_detail">detail_flat</field>
<field name="type">sum</field>
</record>
<record id="financial_report_10" model="account.financial.report">
<field name="name">ACTIF</field>
<field name="sequence">13</field>
<field name="parent_id" ref="financial_report_9"/>
<field name="style_overwrite" eval="2"/>
<field name="sign" eval="1"/>
<field name="display_detail">detail_flat</field>
<field name="type">sum</field>
</record>
<record id="financial_report_43" model="account.financial.report">
<field name="name">ACTIF CIRCULANTS</field>
<field name="sequence">14</field>
<field name="parent_id" ref="financial_report_10"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">detail_flat</field>
<field name="type">sum</field>
</record>
<record id="financial_report_11" model="account.financial.report">
<field name="name">PASSIF</field>
<field name="sequence">28</field>
<field name="parent_id" ref="financial_report_9"/>
<field name="style_overwrite" eval="2"/>
<field name="sign" eval="1"/>
<field name="display_detail">detail_flat</field>
<field name="type">sum</field>
</record>
<record id="financial_report_13" model="account.financial.report">
<field name="name">Tr&#233;sorerie</field>
<field name="sequence">15</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_14" model="account.financial.report">
<field name="name">Cr&#233;ances r&#233;sultant de livraisons et prestations</field>
<field name="sequence">17</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_15" model="account.financial.report">
<field name="name">Autres cr&#233;ances &#224; court terme</field>
<field name="sequence">18</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_16" model="account.financial.report">
<field name="name">Stocks et prestations non factur&#233;es</field>
<field name="sequence">19</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_17" model="account.financial.report">
<field name="name">Actifs de r&#233;gularisation (transitoires)</field>
<field name="sequence">20</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_18" model="account.financial.report">
<field name="name">ACTIF IMMOBILISES</field>
<field name="sequence">21</field>
<field name="parent_id" ref="financial_report_10"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">detail_with_hierarchy</field>
<field name="type">sum</field>
</record>
<record id="financial_report_19" model="account.financial.report">
<field name="name">Immobilisations financi&#232;res</field>
<field name="sequence">22</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_20" model="account.financial.report">
<field name="name">Participations</field>
<field name="sequence">23</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_21" model="account.financial.report">
<field name="name">Immobilisations corporelles meubles</field>
<field name="sequence">24</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_22" model="account.financial.report">
<field name="name">Immobilisation incorporelles</field>
<field name="sequence">26</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_23" model="account.financial.report">
<field name="name">Capital non vers&#233; : capital social, capital de fondation</field>
<field name="sequence">27</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_24" model="account.financial.report">
<field name="name">DETTES A COURT TERME</field>
<field name="sequence">29</field>
<field name="parent_id" ref="financial_report_11"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">sum</field>
</record>
<record id="financial_report_25" model="account.financial.report">
<field name="name">Dettes &#224; court terme r&#233;sultant d&#8217;achats et de prestations de services</field>
<field name="sequence">30</field>
<field name="parent_id" ref="financial_report_24"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_26" model="account.financial.report">
<field name="name">Dettes &#224; court terme r&#233;mun&#233;r&#233;s</field>
<field name="sequence">31</field>
<field name="parent_id" ref="financial_report_24"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_27" model="account.financial.report">
<field name="name">Autres dettes &#224; court terme</field>
<field name="sequence">32</field>
<field name="parent_id" ref="financial_report_24"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_29" model="account.financial.report">
<field name="name">Passifs de r&#233;gularisation (transitoires) et provisions &#224; court terme</field>
<field name="sequence">33</field>
<field name="parent_id" ref="financial_report_24"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_30" model="account.financial.report">
<field name="name">DETTES A LONG TERME</field>
<field name="sequence">34</field>
<field name="parent_id" ref="financial_report_11"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">sum</field>
</record>
<record id="financial_report_31" model="account.financial.report">
<field name="name">Dettes &#224; long terme r&#233;mun&#233;r&#233;es</field>
<field name="sequence">35</field>
<field name="parent_id" ref="financial_report_30"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_33" model="account.financial.report">
<field name="name">Provisions &#224; long termes et provisions l&#233;gales</field>
<field name="sequence">37</field>
<field name="parent_id" ref="financial_report_30"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_36" model="account.financial.report">
<field name="name">CAPITAUX PROPRES</field>
<field name="sequence">38</field>
<field name="parent_id" ref="financial_report_11"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">sum</field>
</record>
<record id="financial_report_37" model="account.financial.report">
<field name="name">Autres dettes &#224; long terme</field>
<field name="sequence">36</field>
<field name="parent_id" ref="financial_report_30"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_38" model="account.financial.report">
<field name="name">Capital social</field>
<field name="sequence">39</field>
<field name="parent_id" ref="financial_report_36"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_39" model="account.financial.report">
<field name="name">R&#233;serves / b&#233;n&#233;fices et pertes report&#233;s</field>
<field name="sequence">40</field>
<field name="parent_id" ref="financial_report_36"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
</data>
</openerp>
+218
View File
@@ -0,0 +1,218 @@
<openerp>
<data noupdate="1">
<record id="financial_report_44" model="account.financial.report">
<field name="name">COMPTE DE RESULTAT</field>
<field name="sequence">44</field>
<field name="sign" eval="1"/>
<field name="display_detail">detail_flat</field>
<field name="type">sum</field>
</record>
<record id="financial_report_45" model="account.financial.report">
<field name="name">Produits net des ventes de biens et de prestations de services</field>
<field name="sequence">48</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_46" model="account.financial.report">
<field name="name">B&#233;n&#233;fice ou perte de l'exercice</field>
<field name="sequence">41</field>
<field name="parent_id" ref="financial_report_36"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_47" model="account.financial.report">
<field name="name">Actifs &#224; court terme cot&#233;s en bourse</field>
<field name="sequence">16</field>
<field name="parent_id" ref="financial_report_43"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_48" model="account.financial.report">
<field name="name">Charges de mat&#233;riel</field>
<field name="sequence">51</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_49" model="account.financial.report">
<field name="name">Charges de personnel</field>
<field name="sequence">53</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_50" model="account.financial.report">
<field name="name">Autres charges d&#8216;exploitation</field>
<field name="sequence">55</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_51" model="account.financial.report">
<field name="name">Amortissement et corrections de valeur des postes sur immobilisations corporelles</field>
<field name="sequence">57</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_52" model="account.financial.report">
<field name="name">Produits financiers</field>
<field name="sequence">59</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_53" model="account.financial.report">
<field name="name">R&#233;sultat hors exploitation</field>
<field name="sequence">63</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_54" model="account.financial.report">
<field name="name">R&#233;sultat exceptionnel</field>
<field name="sequence">64</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_55" model="account.financial.report">
<field name="name">Imp&#244;ts directs</field>
<field name="sequence">66</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_57" model="account.financial.report">
<field name="name">Variation des stocks et de produits finis et semi-finis et variation des prestations de services non factur&#233;s</field>
<field name="sequence">49</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_58" model="account.financial.report">
<field name="name">= CHIFFRE D&#8217;AFFAIRES SUR VENTES ET PRESTATIONS DE SERVICES</field>
<field name="sequence">50</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_59" model="account.financial.report">
<field name="name">= RESULTAT BRUT APRES CHARGES DE MATIERES ET MARCHANDISES</field>
<field name="sequence">52</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_60" model="account.financial.report">
<field name="name">= RESULTAT APRES CHARGES DE PERSONNEL</field>
<field name="sequence">54</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_61" model="account.financial.report">
<field name="name">= EBITDA</field>
<field name="sequence">56</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_62" model="account.financial.report">
<field name="name">= EBIT</field>
<field name="sequence">58</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_63" model="account.financial.report">
<field name="name">Charges financi&#232;res</field>
<field name="sequence">60</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_65" model="account.financial.report">
<field name="name">= RESULTAT D'EXPLOITATION AVANT IMPOTS (EBT)</field>
<field name="sequence">61</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_66" model="account.financial.report">
<field name="name">R&#233;sultat des activit&#233;s annexes des exploitations</field>
<field name="sequence">62</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_67" model="account.financial.report">
<field name="name">= RESULTAT AVANT IMPOTS</field>
<field name="sequence">65</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="3"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_68" model="account.financial.report">
<field name="name">= BENEFICE OU PERTE DE L'EXERCICE</field>
<field name="sequence">67</field>
<field name="parent_id" ref="financial_report_44"/>
<field name="style_overwrite" eval="2"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
<record id="financial_report_69" model="account.financial.report">
<field name="name">Immobilisations corporelles immeubles</field>
<field name="sequence">25</field>
<field name="parent_id" ref="financial_report_18"/>
<field name="style_overwrite" eval="4"/>
<field name="sign" eval="1"/>
<field name="display_detail">no_detail</field>
<field name="type">accounts</field>
</record>
</data>
</openerp>
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -155,7 +155,7 @@ class mail_mail(osv.Model):
if context is None:
context = {}
if partner and partner.user_ids:
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
base_url = self.pool.get('ir.config_parameter').get_param(cr, SUPERUSER_ID, 'web.base.url')
mail_model = mail.model or 'mail.thread'
url = urljoin(base_url, self.pool[mail_model]._get_access_link(cr, uid, mail, partner, context=context))
return "<span class='oe_mail_footer_access'><small>%(access_msg)s <a style='color:inherit' href='%(portal_link)s'>%(portal_msg)s</a></small></span>" % {
+7 -3
View File
@@ -652,8 +652,8 @@ openerp.mail = function (session) {
if (self.flag_post) {
return;
}
self.flag_post = true;
if (this.do_check_attachment_upload() && (this.attachment_ids.length || this.$('textarea').val().match(/\S+/))) {
self.flag_post = true;
if (this.is_log) {
this.do_send_message_post([], this.is_log);
}
@@ -880,7 +880,11 @@ openerp.mail = function (session) {
self.parent_thread.message_fetch(this.domain, this.context, false, function (arg, data) {
self.id = false;
// insert the message on dom after this message
self.parent_thread.switch_new_message(data, self.$el);
var element = self.$el;
if (self.thread_level === 0){
element = element.parent();
}
self.parent_thread.switch_new_message(data, element);
self.animated_destroy(200);
});
@@ -1943,7 +1947,7 @@ openerp.mail = function (session) {
'show_compact_message': this.action.params.view_mailbox ? false : 1,
'view_inbox': false,
'emails_from_on_composer': false,
'fetch_limit': 1000 // allow inbox to load all children messages
'fetch_limit': 30 // allow inbox to load all children messages
}, this.action.params);
},
@@ -20,10 +20,8 @@
self.$target.find('a.js_subscribe_btn')
.attr("disabled", data.is_subscriber && data.email.length ? "disabled" : false);
self.$target.removeClass("hidden");
if (data.is_subscriber) {
self.$target.find('.js_subscribe_btn').addClass('hidden');
self.$target.find('.js_subscribed_btn').removeClass('hidden');
}
self.$target.find('.js_subscribe_btn').toggleClass('hidden', !!data.is_subscriber);
self.$target.find('.js_subscribed_btn').toggleClass('hidden', !data.is_subscriber);
});
// not if editable mode to allow designer to edit alert field
+9 -2
View File
@@ -737,9 +737,13 @@ class mrp_production(osv.osv):
if context is None:
context = {}
move_obj = self.pool.get('stock.move')
proc_obj = self.pool.get('procurement.order')
for production in self.browse(cr, uid, ids, context=context):
if production.move_created_ids:
move_obj.action_cancel(cr, uid, [x.id for x in production.move_created_ids])
procs = proc_obj.search(cr, uid, [('move_dest_id', 'in', [x.id for x in production.move_lines])], context=context)
if procs:
proc_obj.cancel(cr, uid, procs, context=context)
move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines])
self.write(cr, uid, ids, {'state': 'cancel'})
# Put related procurements in exception
@@ -1057,7 +1061,8 @@ class mrp_production(osv.osv):
source_location_id = production.product_id.property_stock_production.id
destination_location_id = production.location_dest_id.id
procs = proc_obj.search(cr, uid, [('production_id', '=', production.id)], context=context)
procurement_id = procs and procs[0] or False
procurement = procs and\
proc_obj.browse(cr, uid, procs[0], context=context) or False
data = {
'name': production.name,
'date': production.date_planned,
@@ -1069,10 +1074,11 @@ class mrp_production(osv.osv):
'location_id': source_location_id,
'location_dest_id': destination_location_id,
'move_dest_id': production.move_prod_id.id,
'procurement_id': procurement_id,
'procurement_id': procurement and procurement.id,
'company_id': production.company_id.id,
'production_id': production.id,
'origin': production.name,
'group_id': procurement and procurement.group_id.id,
}
move_id = stock_move.create(cr, uid, data, context=context)
#a phantom bom cannot be used in mrp order so it's ok to assume the list returned by action_confirm
@@ -1157,6 +1163,7 @@ class mrp_production(osv.osv):
'price_unit': product.standard_price,
'origin': production.name,
'warehouse_id': loc_obj.get_warehouse(cr, uid, production.location_src_id, context=context),
'group_id': production.move_prod_id.group_id.id,
}, context=context)
if prev_move:
+39 -31
View File
@@ -23,6 +23,7 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
from openerp import SUPERUSER_ID
class procurement_rule(osv.osv):
@@ -69,47 +70,54 @@ class procurement_order(osv.osv):
return False
return True
def _get_date_planned(self, cr, uid, procurement, context=None):
format_date_planned = datetime.strptime(procurement.date_planned,
DEFAULT_SERVER_DATETIME_FORMAT)
date_planned = format_date_planned - relativedelta(days=procurement.product_id.produce_delay or 0.0)
date_planned = date_planned - relativedelta(days=procurement.company_id.manufacturing_lead)
return date_planned
def _prepare_mo_vals(self, cr, uid, procurement, context=None):
res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
newdate = self._get_date_planned(cr, uid, procurement, context=context)
bom_obj = self.pool.get('mrp.bom')
if procurement.bom_id:
bom_id = procurement.bom_id.id
routing_id = procurement.bom_id.routing_id.id
else:
properties = [x.id for x in procurement.property_ids]
bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
properties=properties, context=context)
bom = bom_obj.browse(cr, uid, bom_id, context=context)
routing_id = bom.routing_id.id
return {
'origin': procurement.origin,
'product_id': procurement.product_id.id,
'product_qty': procurement.product_qty,
'product_uom': procurement.product_uom.id,
'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
'product_uos': procurement.product_uos and procurement.product_uos.id or False,
'location_src_id': procurement.location_id.id,
'location_dest_id': procurement.location_id.id,
'bom_id': bom_id,
'routing_id': routing_id,
'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
'move_prod_id': res_id,
'company_id': procurement.company_id.id,
}
def make_mo(self, cr, uid, ids, context=None):
""" Make Manufacturing(production) order from procurement
@return: New created Production Orders procurement wise
"""
res = {}
company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
production_obj = self.pool.get('mrp.production')
bom_obj = self.pool.get('mrp.bom')
procurement_obj = self.pool.get('procurement.order')
for procurement in procurement_obj.browse(cr, uid, ids, context=context):
if self.check_bom_exists(cr, uid, [procurement.id], context=context):
if procurement.bom_id:
bom_id = procurement.bom_id.id
routing_id = procurement.bom_id.routing_id.id
else:
properties = [x.id for x in procurement.property_ids]
bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
properties=properties, context=context)
bom = bom_obj.browse(cr, uid, bom_id, context=context)
routing_id = bom.routing_id.id
res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
newdate = datetime.strptime(procurement.date_planned, '%Y-%m-%d %H:%M:%S') - relativedelta(days=procurement.product_id.produce_delay or 0.0)
newdate = newdate - relativedelta(days=company.manufacturing_lead)
#create the MO as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
produce_id = production_obj.create(cr, SUPERUSER_ID, {
'origin': procurement.origin,
'product_id': procurement.product_id.id,
'product_qty': procurement.product_qty,
'product_uom': procurement.product_uom.id,
'product_uos_qty': procurement.product_uos and procurement.product_uos_qty or False,
'product_uos': procurement.product_uos and procurement.product_uos.id or False,
'location_src_id': procurement.location_id.id,
'location_dest_id': procurement.location_id.id,
'bom_id': bom_id,
'routing_id': routing_id,
'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
'move_prod_id': res_id,
'company_id': procurement.company_id.id,
})
vals = self._prepare_mo_vals(cr, uid, procurement, context=context)
produce_id = production_obj.create(cr, SUPERUSER_ID, vals, context=context)
res[procurement.id] = produce_id
self.write(cr, uid, [procurement.id], {'production_id': produce_id})
self.production_order_create_note(cr, uid, procurement, context=context)
+3 -1
View File
@@ -37,7 +37,9 @@ class pad_common(osv.osv_memory):
s = string.ascii_uppercase + string.digits
salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(10)])
#path
path = '%s-%s-%s' % (cr.dbname.replace('_','-'), self._name, salt)
# etherpad hardcodes pad id length limit to 50
path = '-%s-%s' % (self._name, salt)
path = '%s%s' % (cr.dbname.replace('_','-')[0:50 - len(path)], path)
# contruct the url
url = '%s/p/%s' % (pad["server"], path)
+4 -2
View File
@@ -57,6 +57,8 @@ class AcquirerBuckaroo(osv.Model):
return values[key]
return ''
values = dict(values or {})
if inout == 'out':
if 'BRQ_SIGNATURE' in values:
del values['BRQ_SIGNATURE']
@@ -81,12 +83,12 @@ class AcquirerBuckaroo(osv.Model):
'Brq_amount': tx_values['amount'],
'Brq_currency': tx_values['currency'] and tx_values['currency'].name or '',
'Brq_invoicenumber': tx_values['reference'],
'brq_test' : True,
'brq_test': False if acquirer.environment == 'prod' else True,
'Brq_return': '%s' % urlparse.urljoin(base_url, BuckarooController._return_url),
'Brq_returncancel': '%s' % urlparse.urljoin(base_url, BuckarooController._cancel_url),
'Brq_returnerror': '%s' % urlparse.urljoin(base_url, BuckarooController._exception_url),
'Brq_returnreject': '%s' % urlparse.urljoin(base_url, BuckarooController._reject_url),
'Brq_culture': 'en-US',
'Brq_culture': (partner_values.get('lang') or 'en_US').replace('_', '-'),
})
if buckaroo_tx_values.get('return_url'):
buckaroo_tx_values['add_returndata'] = {'return_url': '%s' % buckaroo_tx_values.pop('return_url')}
+2 -2
View File
@@ -224,10 +224,10 @@ class PaymentTxOgone(osv.Model):
def _ogone_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
invalid_parameters = []
# TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details
# TODO: txn_id: should be false at draft, set afterwards, and verified with txn details
if tx.acquirer_reference and data.get('PAYID') != tx.acquirer_reference:
invalid_parameters.append(('PAYID', data.get('PAYID'), tx.acquirer_reference))
# check what is buyed
# check what is bought
if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0:
invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount))
if data.get('currency') != tx.currency_id.name:
+9 -5
View File
@@ -871,7 +871,15 @@ class pos_order(osv.osv):
'name': order.name + ': ' + (data.get('payment_name', '') or ''),
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner(order.partner_id).id or False,
}
account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context)
journal_id = data.get('journal', False)
statement_id = data.get('statement_id', False)
assert journal_id or statement_id, "No statement_id or journal_id passed to the method!"
journal = self.pool['account.journal'].browse(cr, uid, journal_id, context=context)
# use the company of the journal and not of the current user
company_cxt = dict(context, force_company=journal.company_id.id)
account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=company_cxt)
args['account_id'] = (order.partner_id and order.partner_id.property_account_receivable \
and order.partner_id.property_account_receivable.id) or (account_def and account_def.id) or False
@@ -884,10 +892,6 @@ class pos_order(osv.osv):
context.pop('pos_session_id', False)
journal_id = data.get('journal', False)
statement_id = data.get('statement_id', False)
assert journal_id or statement_id, "No statement_id or journal_id passed to the method!"
for statement in order.session_id.statement_ids:
if statement.id == statement_id:
journal_id = statement.journal_id.id
@@ -13,6 +13,7 @@
<field name="sequence_id" ref="seq_picking_type_posout"/>
<field name="default_location_src_id" ref="stock.stock_location_stock"/>
<field name="default_location_dest_id" ref="stock.stock_location_customers"/>
<field name="warehouse_id" eval="False"/>
<field name="code">outgoing</field>
</record>
</data>
+1 -1
View File
@@ -716,7 +716,7 @@
</group>
<group string="Receipt" >
<field name="receipt_header" string="Header" placeholder="A custom receipt header message"/>
<field name="receipt_footer" string="Footer" placeholder="A custom receipt header footage"/>
<field name="receipt_footer" string="Footer" placeholder="A custom receipt footer message"/>
</group>
</sheet>
+4 -2
View File
@@ -109,7 +109,8 @@ class pos_details(report_sxw.rml_parse):
statement_line_obj = self.pool.get("account.bank.statement.line")
pos_order_obj = self.pool.get("pos.order")
user_ids = form['user_ids'] or self._get_all_users()
pos_ids = pos_order_obj.search(self.cr, self.uid, [('date_order','>=',form['date_start'] + ' 00:00:00'),('date_order','<=',form['date_end'] + ' 23:59:59'),('state','in',['paid','invoiced','done']),('user_id','in',user_ids)])
company_id = self.pool['res.users'].browse(self.cr, self.uid, self.uid).company_id.id
pos_ids = pos_order_obj.search(self.cr, self.uid, [('date_order','>=',form['date_start'] + ' 00:00:00'),('date_order','<=',form['date_end'] + ' 23:59:59'),('state','in',['paid','invoiced','done']),('user_id','in',user_ids), ('company_id', '=', company_id)])
data={}
if pos_ids:
st_line_ids = statement_line_obj.search(self.cr, self.uid, [('pos_statement_id', 'in', pos_ids)])
@@ -157,7 +158,8 @@ class pos_details(report_sxw.rml_parse):
account_tax_obj = self.pool.get('account.tax')
user_ids = form['user_ids'] or self._get_all_users()
pos_order_obj = self.pool.get('pos.order')
pos_ids = pos_order_obj.search(self.cr, self.uid, [('date_order','>=',form['date_start'] + ' 00:00:00'),('date_order','<=',form['date_end'] + ' 23:59:59'),('state','in',['paid','invoiced','done']),('user_id','in',user_ids)])
company_id = self.pool['res.users'].browse(self.cr, self.uid, self.uid).company_id.id
pos_ids = pos_order_obj.search(self.cr, self.uid, [('date_order','>=',form['date_start'] + ' 00:00:00'),('date_order','<=',form['date_end'] + ' 23:59:59'),('state','in',['paid','invoiced','done']),('user_id','in',user_ids), ('company_id', '=', company_id)])
for order in pos_order_obj.browse(self.cr, self.uid, pos_ids):
for line in order.lines:
line_taxes = account_tax_obj.compute_all(self.cr, self.uid, line.product_id.taxes_id, line.price_unit * (1-(line.discount or 0.0)/100.0), line.qty, product=line.product_id, partner=line.order_id.partner_id or False)
+9 -7
View File
@@ -153,24 +153,25 @@ openerp.point_of_sale.load_db = function load_db(instance, module){
this.cache[store] = data;
},
_product_search_string: function(product){
var str = '' + product.id + ':' + product.display_name;
var str = product.display_name;
if (product.barcode) {
str += '|' + product.barcode;
}
if (product.default_code) {
str += '|' + product.default_code.replace(':','');
str += '|' + product.default_code;
}
if (product.description) {
str += '|' + product.description.replace(':','');
str += '|' + product.description;
}
if (product.description_sale) {
str += '|' + product.description_sale.replace(':','');
str += '|' + product.description_sale;
}
var packagings = this.packagings_by_product_tmpl_id[product.product_tmpl_id] || [];
for (var i = 0; i < packagings.length; i++) {
str += '|' + packagings[i].barcode;
}
return str + '\n';
str = product.id + ':' + str.replace(':','') + '\n';
return str;
},
add_products: function(products){
var stored_categories = this.product_by_category_id;
@@ -227,7 +228,7 @@ openerp.point_of_sale.load_db = function load_db(instance, module){
}
},
_partner_search_string: function(partner){
var str = '' + partner.id + ':' + partner.name;
var str = partner.name;
if(partner.barcode){
str += '|' + partner.barcode;
}
@@ -243,7 +244,8 @@ openerp.point_of_sale.load_db = function load_db(instance, module){
if(partner.email){
str += '|' + partner.email;
}
return str + '\n';
str = '' + partner.id + ':' + str.replace(':','') + '\n';
return str;
},
add_partners: function(partners){
var updated_count = 0;
+31 -12
View File
@@ -183,7 +183,7 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
},
},{
model: 'account.tax',
fields: ['name','amount', 'price_include', 'type'],
fields: ['name','amount', 'price_include', 'include_base_amount', 'type'],
domain: null,
loaded: function(self,taxes){
self.taxes = taxes;
@@ -1036,7 +1036,7 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
},
get_base_price: function(){
var rounding = this.pos.currency.rounding;
return round_pr(round_pr(this.get_unit_price() * this.get_quantity(),rounding) * (1- this.get_discount()/100.0),rounding);
return round_pr(this.get_unit_price() * this.get_quantity() * (1 - this.get_discount()/100), rounding);
},
get_display_price: function(){
return this.get_base_price();
@@ -1055,6 +1055,22 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
get_tax: function(){
return this.get_all_prices().tax;
},
get_applicable_taxes: function(){
// Shenaningans because we need
// to keep the taxes ordering.
var ptaxes_ids = this.get_product().taxes_id;
var ptaxes_set = {};
for (var i = 0; i < ptaxes_ids.length; i++) {
ptaxes_set[ptaxes_ids[i]] = true;
}
var taxes = [];
for (var i = 0; i < this.pos.taxes.length; i++) {
if (ptaxes_set[this.pos.taxes[i].id]) {
taxes.push(this.pos.taxes[i]);
}
}
return taxes;
},
get_tax_details: function(){
return this.get_all_prices().taxDetails;
},
@@ -1074,12 +1090,10 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
var totalNoTax = base;
var product = this.get_product();
var taxes_ids = product.taxes_id;
var taxes = self.pos.taxes;
var taxes = this.get_applicable_taxes();
var taxtotal = 0;
var taxdetail = {};
_.each(taxes_ids, function(el) {
var tax = _.detect(taxes, function(t) {return t.id === el;});
_.each(taxes, function(tax) {
if (tax.price_include) {
var tmp;
if (tax.type === "percent") {
@@ -1102,7 +1116,13 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
} 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;
}
taxtotal += tmp;
totalTax += tmp;
taxdetail[tax.id] = tmp;
@@ -1157,6 +1177,10 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
this.trigger('change',this);
}
},
// returns the payment type: 'cash' | 'bank'
get_type: function(){
return this.cashregister.journal.type
},
// returns the associated cashregister
//exports as JSON for server communication
export_as_JSON: function(){
@@ -1565,11 +1589,6 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
get_tax_details: function(){
var details = {};
var fulldetails = [];
var taxes_by_id = {};
for(var i = 0; i < this.pos.taxes.length; i++){
taxes_by_id[this.pos.taxes[i].id] = this.pos.taxes[i];
}
this.orderlines.each(function(line){
var ldetails = line.get_tax_details();
@@ -1582,7 +1601,7 @@ openerp.point_of_sale.load_models = function load_models(instance, module){ //mo
for(var id in details){
if(details.hasOwnProperty(id)){
fulldetails.push({amount: details[id], tax: taxes_by_id[id], name: taxes_by_id[id].name});
fulldetails.push({amount: details[id], tax: this.pos.taxes_by_id[id], name: this.pos.taxes_by_id[id].name});
}
}
@@ -1641,6 +1641,17 @@ openerp.point_of_sale.load_screens = function load_screens(instance, module){ //
return;
}
var plines = currentOrder.get('paymentLines').models;
for (var i = 0; i < plines.length; i++) {
if (plines[i].get_type() === 'bank' && plines[i].get_amount() < 0) {
this.pos_widget.screen_selector.show_popup('error',{
'message': _t('Negative Bank Payment'),
'comment': _t('You cannot have a negative amount in a Bank payment. Use a cash payment method to return money to the customer.'),
});
return;
}
}
if (!order.is_paid() || this.invoicing) {
return;
}
@@ -8,7 +8,6 @@
<field name="priority">20</field>
<field name="arch" type="xml">
<kanban class="oe_portal_project_issue">
<field name="priority"/>
<field name="user_email"/>
<field name="user_id"/>
<field name="date_deadline"/>
+45 -33
View File
@@ -247,19 +247,27 @@ class product_pricelist(osv.osv):
results = {}
for product, qty, partner in products_by_qty_by_partner:
uom_price_already_computed = False
results[product.id] = 0.0
price = False
rule_id = False
price = False
# Final unit price is computed according to `qty` in the `qty_uom_id` UoM.
# An intermediary unit price may be computed according to a different UoM, in
# which case the price_uom_id contains that UoM.
# The final price will be converted to match `qty_uom_id`.
qty_uom_id = context.get('uom') or product.uom_id.id
price_uom_id = product.uom_id.id
qty_in_product_uom = qty
if qty_uom_id != product.uom_id.id:
try:
qty_in_product_uom = product_uom_obj._compute_qty(
cr, uid, context['uom'], qty, product.uom_id.id or product.uos_id.id)
except except_orm:
# Ignored - incompatible UoM in context, use default product UoM
pass
for rule in items:
if 'uom' in context and product.uom_id and context['uom'] != product.uom_id.id:
try:
qty_in_product_uom = product_uom_obj._compute_qty(cr, uid, context['uom'], qty, product.uom_id.id, dict(context.items() + [('raise-exception', False)]))
except except_orm:
qty_in_product_uom = qty
else:
qty_in_product_uom = qty
if rule.min_quantity and qty_in_product_uom<rule.min_quantity:
if rule.min_quantity and qty_in_product_uom < rule.min_quantity:
continue
if is_product_template:
if rule.product_tmpl_id and product.id != rule.product_tmpl_id.id:
@@ -287,7 +295,7 @@ class product_pricelist(osv.osv):
rule.base_pricelist_id, [(product,
qty, False)], context=context)[product.id]
ptype_src = rule.base_pricelist_id.currency_id.id
uom_price_already_computed = True
price_uom_id = qty_uom_id
price = currency_obj.compute(cr, uid,
ptype_src, pricelist.currency_id.id,
price_tmp, round=False,
@@ -302,12 +310,10 @@ class product_pricelist(osv.osv):
seller = product.seller_ids[0]
if seller:
qty_in_seller_uom = qty
from_uom = context.get('uom') or product.uom_id.id
seller_uom = seller.product_uom and seller.product_uom.id or False
if seller_uom and from_uom and from_uom != seller_uom:
qty_in_seller_uom = product_uom_obj._compute_qty(cr, uid, from_uom, qty, to_uom_id=seller_uom)
else:
uom_price_already_computed = True
seller_uom = seller.product_uom.id
if qty_uom_id != seller_uom:
qty_in_seller_uom = product_uom_obj._compute_qty(cr, uid, qty_uom_id, qty, to_uom_id=seller_uom)
price_uom_id = seller_uom
for line in seller.pricelist_ids:
if line.min_quantity <= qty_in_seller_uom:
price = line.price
@@ -317,34 +323,40 @@ class product_pricelist(osv.osv):
price_types[rule.base] = price_type_obj.browse(cr, uid, int(rule.base))
price_type = price_types[rule.base]
uom_price_already_computed = True
price = currency_obj.compute(cr, uid,
# price_get returns the price in the context UoM, i.e. qty_uom_id
price_uom_id = qty_uom_id
price = currency_obj.compute(
cr, uid,
price_type.currency_id.id, pricelist.currency_id.id,
product_obj._price_get(cr, uid, [product],
price_type.field, context=context)[product.id], round=False, context=context)
product_obj._price_get(cr, uid, [product], price_type.field, context=context)[product.id],
round=False, context=context)
if price is not False:
price_limit = price
price = price * (1.0+(rule.price_discount or 0.0))
if rule.price_round:
price = tools.float_round(price, precision_rounding=rule.price_round)
if context.get('uom'):
# compute price_surcharge based on reference uom
factor = product_uom_obj.browse(cr, uid, context.get('uom'), context=context).factor
else:
factor = 1.0
price += (rule.price_surcharge or 0.0) / factor
convert_to_price_uom = (lambda price: product_uom_obj._compute_price(
cr, uid, product.uom_id.id,
price, price_uom_id))
if rule.price_surcharge:
price_surcharge = convert_to_price_uom(rule.price_surcharge)
price += price_surcharge
if rule.price_min_margin:
price = max(price, price_limit+rule.price_min_margin)
price_min_margin = convert_to_price_uom(rule.price_min_margin)
price = max(price, price_limit + price_min_margin)
if rule.price_max_margin:
price = min(price, price_limit+rule.price_max_margin)
price_max_margin = convert_to_price_uom(rule.price_max_margin)
price = min(price, price_limit + price_max_margin)
rule_id = rule.id
break
if price:
if 'uom' in context and not uom_price_already_computed:
uom = product.uos_id or product.uom_id
price = product_uom_obj._compute_price(cr, uid, uom.id, price, context['uom'])
# Final price conversion to target UoM
price = product_uom_obj._compute_price(cr, uid, price_uom_id, price, qty_uom_id)
results[product.id] = (price, rule_id)
return results
+4 -6
View File
@@ -177,7 +177,8 @@ class product_uom(osv.osv):
return amount
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):
if not from_uom_id or not price or not to_uom_id:
if (not from_uom_id or not price or not to_uom_id
or (to_uom_id == from_uom_id)):
return price
from_unit, to_unit = self.browse(cr, uid, [from_uom_id, to_uom_id])
if from_unit.category_id.id != to_unit.category_id.id:
@@ -890,11 +891,8 @@ class product_product(osv.osv):
return dict.fromkeys(ids, True)
def _get_name_template_ids(self, cr, uid, ids, context=None):
result = set()
template_ids = self.pool.get('product.product').search(cr, uid, [('product_tmpl_id', 'in', ids)])
for el in template_ids:
result.add(el)
return list(result)
return list(set(template_ids))
def _get_image_variant(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
@@ -924,7 +922,7 @@ class product_product(osv.osv):
_columns = {
'price': fields.function(_product_price, type='float', string='Price', digits_compute=dp.get_precision('Product Price')),
'price_extra': fields.function(_get_price_extra, type='float', string='Variant Extra Price', help="This is the sum of the extra price of all attributes"),
'price_extra': fields.function(_get_price_extra, type='float', string='Variant Extra Price', help="This is the sum of the extra price of all attributes", digits_compute=dp.get_precision('Product Price')),
'lst_price': fields.function(_product_lst_price, fnct_inv=_set_product_lst_price, type='float', string='Public Price', digits_compute=dp.get_precision('Product Price')),
'code': fields.function(_product_code, type='char', string='Internal Reference'),
'partner_ref' : fields.function(_product_partner_ref, type='char', string='Customer ref'),
+6 -1
View File
@@ -15,7 +15,7 @@
<filter string="Consumable" name="consumable" icon="terp-accessories-archiver" domain="[('type','=','consu')]" help="Consumable products"/>
<separator/>
<filter string="Can be Sold" name="filter_to_sell" icon="terp-accessories-archiver-minus" domain="[('sale_ok','=',1)]"/>
<field name="categ_id"/>
<field name="categ_id" filter_domain="[('categ_id', 'child_of', self)]"/>
<field string="Product Variant" name="product_variant_ids" filter_domain="['|', ('product_variant_ids.name','ilike',self), ('product_variant_ids.attribute_value_ids.name','ilike',self)]"/>
<field name="company_id"/>
<field name="pricelist_id" widget="selection" context="{'pricelist': self}" filter_domain="[]" groups="product.group_sale_pricelist"/> <!-- Keep widget=selection on this field to pass numeric `self` value, which is not the case for regular m2o widgets! -->
@@ -257,6 +257,11 @@
<field string="List of Variants" name="product_variant_count" widget="statinfo" />
</button>
</div>
<p class="oe_grey">
<strong>Warning</strong>: adding or deleting attributes
will delete and recreate existing variants and lead
to the loss of its eventual customizations.
</p>
<field name="attribute_line_ids" widget="one2many_list" context="{'show_attribute': False}">
<tree string="Variants" editable="bottom">
<field name="attribute_id"/>
+1 -1
View File
@@ -3,7 +3,7 @@
<lot-line type="fields" name="id">
<code type="field" name="code"/>
<product type="field" name="name"/>
<variant type="field" name="attribute_value_ids"/>
<variant type="field" name="attribute_value_ids.name"/>
<price type="field" name="list_price"/>
<barcode type="field" name="barcode"/>
<currency type="field" name="company_id.currency_id.name"/>
+1 -1
View File
@@ -77,7 +77,7 @@
<barCode><xsl:value-of select="barcode" /></barCode>
</td>
<td>
<para style="nospace"><xsl:value-of select="substring(product, 1, pmaxChars)"/></para><xsl:text>, </xsl:text>
<para style="nospace"><xsl:value-of select="substring(product, 1, $pmaxChars)"/></para><xsl:text>, </xsl:text>
<para style="nospace"><xsl:value-of select="variant"/></para>
</td>
</tr>
@@ -16,6 +16,7 @@ access_product_pricelist_type_partner_manager,product.pricelist.type partner man
access_product_pricelist_partner_manager,product.pricelist partner manager,model_product_pricelist,base.group_partner_manager,1,0,0,0
access_product_product_employee,product.product employee,model_product_product,base.group_user,1,0,0,0
access_product_price_history_employee,prices.history employee,model_product_price_history,base.group_user,1,0,0,0
access_product_price_history_salemanager,prices.history sale manager,product.model_product_price_history,base.group_sale_manager,1,1,1,1
access_product_template_sale_manager,product.template salemanager,model_product_template,base.group_sale_manager,1,1,1,1
access_product_product_sale_manager,product.product salemanager,model_product_product,base.group_sale_manager,1,1,1,1
access_product_category_sale_manager,product.category salemanager,product.model_product_category,base.group_sale_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
16 access_product_pricelist_partner_manager product.pricelist partner manager model_product_pricelist base.group_partner_manager 1 0 0 0
17 access_product_product_employee product.product employee model_product_product base.group_user 1 0 0 0
18 access_product_price_history_employee prices.history employee model_product_price_history base.group_user 1 0 0 0
19 access_product_price_history_salemanager prices.history sale manager product.model_product_price_history base.group_sale_manager 1 1 1 1
20 access_product_template_sale_manager product.template salemanager model_product_template base.group_sale_manager 1 1 1 1
21 access_product_product_sale_manager product.product salemanager model_product_product base.group_sale_manager 1 1 1 1
22 access_product_category_sale_manager product.category salemanager product.model_product_category base.group_sale_manager 1 1 1 1
+46 -1
View File
@@ -15,6 +15,8 @@ class TestPricelist(TransactionCase):
self.datacard_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_46')[1]
self.unit_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_unit')[1]
self.dozen_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_uom_dozen')[1]
self.tonne_id = self.ir_model_data.xmlid_to_res_id(cr, uid, 'product.product_uom_ton')
self.kg_id = self.ir_model_data.xmlid_to_res_id(cr, uid, 'product.product_uom_kgm')
self.public_pricelist_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'list0')[1]
self.sale_pricelist_id = self.product_pricelist.create(cr, uid, {
@@ -64,7 +66,50 @@ class TestPricelist(TransactionCase):
usb_adapter_unit = self.product_product.browse(cr, uid, self.usb_adapter_id, context=unit_context)
usb_adapter_dozen = self.product_product.browse(cr, uid, self.usb_adapter_id, context=dozen_context)
self.assertAlmostEqual(usb_adapter_unit.price*12, usb_adapter_dozen.price)
datacard_unit = self.product_product.browse(cr, uid, self.datacard_id, context=unit_context)
datacard_dozen = self.product_product.browse(cr, uid, self.datacard_id, context=dozen_context)
# price_surcharge applies to product default UoM, here "Units", so surcharge will be multiplied
self.assertAlmostEqual(datacard_unit.price*12, datacard_dozen.price)
def test_20_pricelist_uom(self):
# Verify that the pricelist rules are correctly using the product's default UoM
# as reference, and return a result according to the target UoM (as specific in the context)
cr, uid = self.cr, self.uid
kg, tonne = self.kg_id, self.tonne_id
tonne_price = 100
# make sure 'tonne' resolves down to 1 'kg'.
self.uom.write(cr, uid, tonne, {'rounding': 0.001})
# setup product stored in 'tonnes', with a discounted pricelist for qty > 3 tonnes
spam_id = self.product_product.copy(cr, uid, self.usb_adapter_id,
{ 'name': '1 tonne of spam',
'uom_id': self.tonne_id,
'uos_id': self.tonne_id,
'uom_po_id': self.tonne_id,
'list_price': tonne_price,
})
pricelist_version_id = self.ir_model_data.xmlid_to_res_id(cr, uid, 'product.ver0')
self.registry('product.pricelist.item').create(cr, uid,
{ 'price_version_id': pricelist_version_id,
'sequence': 10,
'name': '3+ tonnes: -10 EUR discount/t',
'base': 1, # based on public price
'min_quantity': 3, # min = 3 tonnes
'price_surcharge': -10, # -10 EUR / tonne
'product_id': spam_id,
})
pricelist_id = self.public_pricelist_id
def test_unit_price(qty, uom, expected_unit_price):
unit_price = self.registry('product.pricelist').price_get(cr, uid, [pricelist_id],
spam_id, qty,
context={'uom': uom})[pricelist_id]
self.assertAlmostEqual(unit_price, expected_unit_price, msg='Computed unit price is wrong')
# Test prices - they are *per unit*, the quantity is only here to match the pricelist rules!
test_unit_price(2, kg, tonne_price / 1000.0)
test_unit_price(2000, kg, tonne_price / 1000.0)
test_unit_price(3500, kg, (tonne_price - 10) / 1000.0)
test_unit_price(2, tonne, tonne_price)
test_unit_price(3, tonne, tonne_price - 10)
+1 -1
View File
@@ -317,7 +317,7 @@
<field name="name">project.project.gantt</field>
<field name="model">project.project</field>
<field name="arch" type="xml">
<gantt date_delay="planned_hours" date_start="date_start" progress="progress_rate" string="Projects">
<gantt date_start="date_start" date_stop="date" progress="progress_rate" string="Projects">
</gantt>
</field>
</record>
@@ -196,7 +196,6 @@
<kanban default_group_by="stage_id">
<field name="stage_id" options='{"group_by_tooltip": {"description": "Description", "legend_priority": "Use of stars"}}'/>
<field name="color"/>
<field name="priority"/>
<field name="user_email"/>
<field name="user_id"/>
<field name="date_deadline"/>
+2 -2
View File
@@ -30,8 +30,8 @@ class res_partner(osv.osv):
Invoice = self.pool['account.invoice']
return {
partner_id: {
'purchase_order_count': PurchaseOrder.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context),
'supplier_invoice_count': Invoice.search_count(cr,uid, [('partner_id', '=', partner_id), ('type','=','in_invoice')], context=context)
'purchase_order_count': PurchaseOrder.search_count(cr,uid, [('partner_id', 'child_of', partner_id)], context=context),
'supplier_invoice_count': Invoice.search_count(cr,uid, [('partner_id', 'child_of', partner_id), ('type','=','in_invoice')], context=context)
}
for partner_id in ids
}
+7 -7
View File
@@ -296,7 +296,8 @@ class purchase_order(osv.osv):
'bid_validity': fields.date('Bid Valid Until', help="Date on which the bid expired"),
'picking_type_id': fields.many2one('stock.picking.type', 'Deliver To', help="This will determine picking type of incoming shipment", required=True,
states={'confirmed': [('readonly', True)], 'approved': [('readonly', True)], 'done': [('readonly', True)]}),
'related_location_id': fields.related('picking_type_id', 'default_location_dest_id', type='many2one', relation='stock.location', string="Related location", store=True),
'related_location_id': fields.related('picking_type_id', 'default_location_dest_id', type='many2one', relation='stock.location', string="Related location", store=True),
'related_usage': fields.related('location_id', 'usage', type='char'),
'shipment_count': fields.function(_count_all, type='integer', string='Incoming Shipments', multi=True),
'invoice_count': fields.function(_count_all, type='integer', string='Invoices', multi=True),
'group_id': fields.many2one('procurement.group', string="Procurement Group"),
@@ -383,8 +384,8 @@ class purchase_order(osv.osv):
if picking_type_id:
picktype = self.pool.get("stock.picking.type").browse(cr, uid, picking_type_id, context=context)
if picktype.default_location_dest_id:
value.update({'location_id': picktype.default_location_dest_id.id})
value.update({'related_location_id': picktype.default_location_dest_id and picktype.default_location_dest_id.id or False})
value.update({'location_id': picktype.default_location_dest_id.id, 'related_usage': picktype.default_location_dest_id.usage})
value.update({'related_location_id': picktype.default_location_dest_id.id})
return {'value': value}
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
@@ -745,14 +746,14 @@ class purchase_order(osv.osv):
'product_uos_qty': min(procurement_qty, diff_quantity),
'move_dest_id': procurement.move_dest_id.id, #move destination is same as procurement destination
'procurement_id': procurement.id,
'invoice_state': procurement.rule_id.invoice_state or (procurement.location_id and procurement.location_id.usage == 'customer' and procurement.invoice_state=='picking' and '2binvoiced') or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale
'invoice_state': procurement.rule_id.invoice_state or (procurement.location_id and procurement.location_id.usage == 'customer' and procurement.invoice_state=='2binvoiced' and '2binvoiced') or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale
'propagate': procurement.rule_id.propagate,
})
diff_quantity -= min(procurement_qty, diff_quantity)
res.append(tmp)
#if the order line has a bigger quantity than the procurement it was for (manually changed or minimal quantity), then
#split the future stock move in two because the route followed may be different.
if diff_quantity > 0:
if float_compare(diff_quantity, 0.0, precision_rounding=order_line.product_uom.rounding) > 0:
move_template['product_uom_qty'] = diff_quantity
move_template['product_uos_qty'] = diff_quantity
res.append(move_template)
@@ -1052,7 +1053,7 @@ class purchase_order_line(osv.osv):
def action_cancel(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
# Calculate the list of purchase orders first
# We will group by PO first, so we do the check only once for each PO
purchase_orders = list(set([x.order_id for x in self.browse(cr, uid, ids, context=context)]))
for purchase in purchase_orders:
if all([l.state == 'cancel' for l in purchase.order_line]):
@@ -1063,7 +1064,6 @@ class purchase_order_line(osv.osv):
res = [user for user in group_uom.users if user.id == uid]
return len(res) and True or False
def onchange_product_id(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
name=False, price_unit=False, state='draft', context=None):
+8 -8
View File
@@ -226,12 +226,12 @@
<group>
<field name="date_order"/>
<field name="origin" attrs="{'invisible': [('origin','=',False)]}"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="picking_type_id" on_change="onchange_picking_type_id(picking_type_id, context)" domain="[('code','=','incoming')]" widget="selection" context="{'special_shortened_wh_name': True}" groups="stock.group_locations"/>
<field name="related_location_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="picking_type_id" on_change="onchange_picking_type_id(picking_type_id, context)" domain="[('code','=','incoming')]" options="{'no_create': True}" context="{'special_shortened_wh_name': True}" groups="stock.group_locations"/>
<field name="related_usage" invisible="1"/>
<field name="dest_address_id" string="Customer Address" on_change="onchange_dest_address_id(dest_address_id, context)"
attrs="{'invisible':['|', ('picking_type_id','=',False), ('related_location_id','!=', False)],
'required': [('picking_type_id','!=',False), ('related_location_id','=', False)]}"
attrs="{'invisible':[('related_usage','!=','customer')],
'required': [('related_usage','=', 'customer')]}"
groups="stock.group_locations"/>
</group>
</group>
@@ -242,7 +242,7 @@
<field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,0,False,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,False,parent.state,context)" context="{'partner_id': parent.partner_id}"/>
<field name="name"/>
<field name="date_planned"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="account_analytic_id" context="{'default_partner_id':parent.partner_id}" groups="purchase.group_analytic_accounting" domain="[('type','not in',('view','template'))]"/>
<field name="product_qty" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id,parent.date_order,parent.fiscal_position,date_planned,name,False,parent.state,context)"/>
<field name="product_uom" groups="product.group_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,False,parent.state,context)"/>
@@ -434,7 +434,7 @@
<field name="taxes_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
<field name="date_planned" widget="date"/>
<field name="account_analytic_id" colspan="2" groups="purchase.group_analytic_accounting"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</group>
</group>
<notebook>
@@ -499,7 +499,7 @@
<field name="taxes_id" widget="many2many_tags"
domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
<field name="date_planned" widget="date" readonly="1"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="account_analytic_id" colspan="4" groups="purchase.group_analytic_accounting"/>
<field name="invoiced"/>
</group>
+15 -2
View File
@@ -19,6 +19,7 @@
#
##############################################################################
from openerp import SUPERUSER_ID
from openerp.osv import fields, osv
from openerp.tools.translate import _
@@ -39,10 +40,12 @@ class stock_move(osv.osv):
for move in self.browse(cr, uid, ids, context=context):
if move.purchase_line_id and move.purchase_line_id.order_id:
order_id = move.purchase_line_id.order_id.id
# update linked purchase order as superuser as the warehouse
# user may not have rights to access purchase.order
if self.pool.get('purchase.order').test_moves_done(cr, uid, [order_id], context=context):
workflow.trg_validate(uid, 'purchase.order', order_id, 'picking_done', cr)
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_done', cr)
if self.pool.get('purchase.order').test_moves_except(cr, uid, [order_id], context=context):
workflow.trg_validate(uid, 'purchase.order', order_id, 'picking_cancel', cr)
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_cancel', cr)
return res
def copy(self, cr, uid, id, default=None, context=None):
@@ -158,6 +161,16 @@ class stock_picking(osv.osv):
invoice_line_obj.write(cr, uid, inv_lines, {'invoice_id': invoice_id}, context=context)
return invoice_id
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
inv_vals = super(stock_picking, self)._get_invoice_vals(cr, uid, key, inv_type, journal_id, move, context=context)
if move.purchase_line_id and move.purchase_line_id.order_id:
purchase = move.purchase_line_id.order_id
inv_vals.update({
'fiscal_position': purchase.fiscal_position.id,
'payment_term': purchase.payment_term_id.id,
})
return inv_vals
class stock_warehouse(osv.osv):
_inherit = 'stock.warehouse'
@@ -7,17 +7,17 @@
<div class="oe_structure"/>
<div class="row">
<div class="col-xs-6">
Shipping address :<br/>
<strong>Shipping address:</strong>
<div t-if="o.dest_address_id">
<div t-field="o.dest_address_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
<div t-if="o.picking_type_id and o.picking_type_id.warehouse_id">
<div t-if="not o.dest_address_id and o.picking_type_id and o.picking_type_id.warehouse_id">
<span t-field="o.picking_type_id.warehouse_id.name"/>
<div t-field="o.picking_type_id.warehouse_id.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
t-field-options='{"widget": "contact", "fields": ["address", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
</div>
@@ -8,16 +8,16 @@
<div class="row mt32 mb32">
<div class="col-xs-6">
Shipping address :<br/>
<strong>Shipping address:</strong>
<div t-if="o.dest_address_id">
<div t-field="o.dest_address_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
<div t-if="o.picking_type_id.warehouse_id">
<div t-if="not o.dest_address_id and o.picking_type_id.warehouse_id">
<span t-field="o.picking_type_id.warehouse_id.name"/>
<div t-field="o.picking_type_id.warehouse_id.partner_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
t-field-options='{"widget": "contact", "fields": ["address", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
</div>
</div>
+9 -5
View File
@@ -22,6 +22,7 @@
from openerp.addons.web.http import Controller, route, request
from openerp.addons.web.controllers.main import _serialize_exception
from openerp.osv import osv
from openerp.tools import html_escape
import simplejson
from werkzeug import exceptions, url_decode
@@ -71,7 +72,7 @@ class ReportController(Controller):
# Misc. route utils
#------------------------------------------------------
@route(['/report/barcode', '/report/barcode/<type>/<path:value>'], type='http', auth="user")
def report_barcode(self, type, value, width=600, height=100):
def report_barcode(self, type, value, width=600, height=100, humanreadable=0):
"""Contoller able to render barcode images thanks to reportlab.
Samples:
<img t-att-src="'/report/barcode/QR/%s' % o.name"/>
@@ -81,11 +82,14 @@ class ReportController(Controller):
:param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39',
'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93',
'UPCA', 'USPS_4State'
:param humanreadable: Accepted values: 0 (default) or 1. 1 will insert the readable value
at the bottom of the output image
"""
try:
width, height = int(width), int(height)
width, height, humanreadable = int(width), int(height), bool(humanreadable)
barcode = createBarcodeDrawing(
type, value=value, format='png', width=width, height=height
type, value=value, format='png', width=width, height=height,
humanReadable = humanreadable
)
barcode = barcode.asString('png')
except (ValueError, AttributeError):
@@ -130,14 +134,14 @@ class ReportController(Controller):
return response
else:
return
except osv.except_osv, e:
except Exception, e:
se = _serialize_exception(e)
error = {
'code': 200,
'message': "Odoo Server Error",
'data': se
}
return request.make_response(simplejson.dumps(error))
return request.make_response(html_escape(simplejson.dumps(error)))
@route(['/report/check_wkhtmltopdf'], type='json', auth="user")
def check_wkhtmltopdf(self):
+4 -7
View File
@@ -519,7 +519,7 @@ class Report(osv.Model):
if specific_paperformat_args and specific_paperformat_args.get('data-report-margin-top'):
command_args.extend(['--margin-top', str(specific_paperformat_args['data-report-margin-top'])])
elif paperformat.margin_top:
else:
command_args.extend(['--margin-top', str(paperformat.margin_top)])
if specific_paperformat_args and specific_paperformat_args.get('data-report-dpi'):
@@ -536,12 +536,9 @@ class Report(osv.Model):
elif paperformat.header_spacing:
command_args.extend(['--header-spacing', str(paperformat.header_spacing)])
if paperformat.margin_left:
command_args.extend(['--margin-left', str(paperformat.margin_left)])
if paperformat.margin_bottom:
command_args.extend(['--margin-bottom', str(paperformat.margin_bottom)])
if paperformat.margin_right:
command_args.extend(['--margin-right', str(paperformat.margin_right)])
command_args.extend(['--margin-left', str(paperformat.margin_left)])
command_args.extend(['--margin-bottom', str(paperformat.margin_bottom)])
command_args.extend(['--margin-right', str(paperformat.margin_right)])
if paperformat.orientation:
command_args.extend(['--orientation', str(paperformat.orientation)])
if paperformat.header_line:
+2 -2
View File
@@ -21,7 +21,7 @@
############################################################################
import faces.pcalendar as pcal
import matplotlib.cbook as cbook
import openerp.tools as tools
import datetime
import sys
@@ -73,7 +73,7 @@ class TimeScale(object):
def create_time_slots(day):
src_slots = dcal.get_working_times(day)
slots = [0, src_slots, 24*60]
slots = tuple(cbook.flatten(slots))
slots = tuple(tools.flatten(slots))
slots = zip(slots[:-1], slots[1:])
#balance non working slots
+5 -2
View File
@@ -7,7 +7,7 @@ import json
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.float_utils import float_repr
class crm_team(osv.Model):
_inherit = 'crm.team'
@@ -37,7 +37,10 @@ class crm_team(osv.Model):
res = {}
for id in ids:
created_domain = [('team_id', '=', id), ('state', 'not in', ['draft', 'cancel']), ('date', '>=', date_begin), ('date', '<=', date_end)]
res[id] = json.dumps(self.__get_bar_values(cr, uid, obj, created_domain, ['price_total', 'date'], 'price_total', 'date', context=context))
values = self.__get_bar_values(cr, uid, obj, created_domain, ['price_total', 'date'], 'price_total', 'date', context=context)
for value in values:
value['value'] = float_repr(value.get('value', 0), precision_digits=self.pool['decimal.precision'].precision_get(cr, uid, 'Account'))
res[id] = json.dumps(values)
return res
_columns = {
-3
View File
@@ -41,9 +41,6 @@ access_product_group_res_partner_sale_manager,res_partner group_sale_manager,bas
access_product_pricelist_version_sale_manager,product.pricelist.version sale_manager,product.model_product_pricelist_version,base.group_sale_manager,1,1,1,1
access_account_invoice_report_salesman,account.invoice.report salesman,account.model_account_invoice_report,base.group_sale_salesman,1,0,0,0
access_account_move_line_salesman,account.move.line invoice,account.model_account_move_line,base.group_sale_salesman,1,0,0,0
access_product_price_history_salemanager,prices.history sale manager,product.model_product_price_history,base.group_sale_manager,1,1,1,1
access_product_price_history_account_user,prices.history account user,product.model_product_price_history,account.group_account_user,1,0,0,0
access_product_price_history_sale_use,prices.history sale use,product.model_product_price_history,base.group_sale_salesman,1,0,0,0
access_sale_order_invoicing_payments,sale.order,model_sale_order,account.group_account_invoice,1,1,0,0
access_sale_order_line_invoicing_payments,sale.order.line,model_sale_order_line,account.group_account_invoice,1,1,0,0
access_account_invoice_report_invoicing_payments,account.invoice.report,account.model_account_invoice_report,account.group_account_invoice,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
41 access_product_pricelist_version_sale_manager product.pricelist.version sale_manager product.model_product_pricelist_version base.group_sale_manager 1 1 1 1
42 access_account_invoice_report_salesman account.invoice.report salesman account.model_account_invoice_report base.group_sale_salesman 1 0 0 0
43 access_account_move_line_salesman account.move.line invoice account.model_account_move_line base.group_sale_salesman 1 0 0 0
access_product_price_history_salemanager prices.history sale manager product.model_product_price_history base.group_sale_manager 1 1 1 1
access_product_price_history_account_user prices.history account user product.model_product_price_history account.group_account_user 1 0 0 0
access_product_price_history_sale_use prices.history sale use product.model_product_price_history base.group_sale_salesman 1 0 0 0
44 access_sale_order_invoicing_payments sale.order model_sale_order account.group_account_invoice 1 1 0 0
45 access_sale_order_line_invoicing_payments sale.order.line model_sale_order_line account.group_account_invoice 1 1 0 0
46 access_account_invoice_report_invoicing_payments account.invoice.report account.model_account_invoice_report account.group_account_invoice 1 0 0 0
+5 -5
View File
@@ -7,13 +7,13 @@
<div class="oe_structure"/>
<div class="row">
<div class="col-xs-6">
<p t-if="o.partner_shipping_id == o.partner_invoice_id">Invoice and shipping address:</p>
<p t-if="o.partner_shipping_id != o.partner_invoice_id">Invoice address: </p>
<strong t-if="o.partner_shipping_id == o.partner_invoice_id">Invoice and shipping address:</strong>
<strong t-if="o.partner_shipping_id != o.partner_invoice_id">Invoice address:</strong>
<div t-field="o.partner_invoice_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
<div t-if="o.partner_shipping_id != o.partner_invoice_id">
<p>Shipping address :</p>
<div t-if="o.partner_shipping_id != o.partner_invoice_id" class="mt8">
<strong>Shipping address:</strong>
<div t-field="o.partner_shipping_id"
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
<p t-if="o.partner_id.vat">VAT: <span t-field="o.partner_id.vat"/></p>
@@ -117,7 +117,7 @@
</div>
<p t-field="o.note" />
<p t-if="o.payment_term">
<p t-if="o.payment_term.note">
<span t-field="o.payment_term.note"/>
</p>
<p t-if="not o.payment_term and o.partner_id.property_payment_term">
+1 -4
View File
@@ -52,10 +52,7 @@ class sale_order_line(osv.osv):
for line in self.browse(cr, uid, ids, context=context):
res[line.id] = 0
if line.product_id:
if line.purchase_price:
res[line.id] = round((line.price_unit*line.product_uos_qty*(100.0-line.discount)/100.0) -(line.purchase_price*line.product_uos_qty), 2)
else:
res[line.id] = round((line.price_unit*line.product_uos_qty*(100.0-line.discount)/100.0) -(line.product_id.standard_price*line.product_uos_qty), 2)
res[line.id] = round(line.price_subtotal - ((line.purchase_price or line.product_id.standard_price) * line.product_uos_qty), 2)
return res
_columns = {
+14
View File
@@ -397,6 +397,8 @@ class stock_move(osv.osv):
sale_line.order_id.partner_id, context=context)[sale_line.order_id.pricelist_id.id]
else:
res['price_unit'] = sale_line.price_unit
uos_coeff = move.product_uom_qty and move.product_uos_qty / move.product_uom_qty or 1.0
res['price_unit'] = res['price_unit'] / uos_coeff
return res
@@ -450,6 +452,18 @@ class stock_picking(osv.osv):
invoice_line_obj.write(cr, uid, created_lines, {'invoice_id': invoice_id}, context=context)
return invoice_id
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
inv_vals = super(stock_picking, self)._get_invoice_vals(cr, uid, key, inv_type, journal_id, move, context=context)
sale = move.picking_id.sale_id
if sale:
inv_vals.update({
'fiscal_position': sale.fiscal_position.id,
'payment_term': sale.payment_term.id,
'user_id': sale.user_id.id,
'team_id': sale.team_id.id,
'name': sale.client_order_ref or '',
})
return inv_vals
class account_invoice(osv.Model):
_inherit = 'account.invoice'
+6
View File
@@ -33,6 +33,12 @@
<field name="picking_policy" required="True"/>
</group>
</xpath>
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="replace">
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
groups="base.group_user"
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,False,product_uos_qty,False,name,parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position, False, parent.warehouse_id, context)"/>
</xpath>
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="replace">
<field name="product_id"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
+1 -1
View File
@@ -19,7 +19,7 @@
#
##############################################################################
{
'name': 'Sale Team',
'name': 'Sales Teams',
'version': '1.0',
'author': 'OpenERP SA',
'category': 'Sales Management',
+7 -6
View File
@@ -22,7 +22,7 @@
from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, float_compare, float_round
from openerp import SUPERUSER_ID
from dateutil.relativedelta import relativedelta
from datetime import datetime
@@ -498,20 +498,21 @@ class procurement_order(osv.osv):
prods = prod_qty[op.product_id.id]['virtual_available']
if prods is None:
continue
if prods <= op.product_min_qty:
if float_compare(prods, op.product_min_qty, precision_rounding=op.product_uom.rounding) <= 0:
qty = max(op.product_min_qty, op.product_max_qty) - prods
reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
if reste > 0:
if float_compare(reste, 0.0, precision_rounding=op.product_uom.rounding) > 0:
qty += op.qty_multiple - reste
if qty < 0:
if float_compare(qty, 0.0, precision_rounding=op.product_uom.rounding) < 0:
continue
qty -= subtract_qty[op.id]
if qty >= 0:
qty_rounded = float_round(qty, precision_rounding=op.product_uom.rounding)
if qty_rounded >= 0:
proc_id = procurement_obj.create(cr, uid,
self._prepare_orderpoint_procurement(cr, uid, op, qty, context=context),
self._prepare_orderpoint_procurement(cr, uid, op, qty_rounded, context=context),
context=context)
tot_procs.append(proc_id)
if use_new_cursor:
+5 -2
View File
@@ -466,12 +466,14 @@ function openerp_picking_widgets(instance){
return new instance.web.Model('stock.picking.type').get_func('search_read')([],[])
.then(function(types){
self.picking_types = types;
type_ids = [];
for(var i = 0; i < types.length; i++){
self.pickings_by_type[types[i].id] = [];
type_ids.push(types[i].id);
}
self.pickings_by_type[0] = [];
return new instance.web.Model('stock.picking').call('search_read',[ [['state','in', ['assigned', 'partially_available']]], [] ], {context: new instance.web.CompoundContext()});
return new instance.web.Model('stock.picking').call('search_read',[ [['state','in', ['assigned', 'partially_available']], ['picking_type_id', 'in', type_ids]], [] ], {context: new instance.web.CompoundContext()});
}).then(function(pickings){
self.pickings = pickings;
@@ -873,7 +875,8 @@ function openerp_picking_widgets(instance){
if (pack_op_ids.length !== 0){
return new instance.web.Model('stock.picking')
.call('action_pack',[[[self.picking.id]], pack_op_ids])
.then(function(){
.then(function(pack){
//TODO: the functionality using current_package_id in context is not needed anymore
instance.session.user_context.current_package_id = false;
return self.refresh_ui(self.picking.id);
});
+7 -6
View File
@@ -1031,9 +1031,9 @@ class stock_picking(osv.osv):
product_uom = {} # Determines UoM used in pack operations
for move in picking.move_lines:
if not product_uom.get(move.product_id.id):
product_uom[move.product_id.id] = move.product_id.uom_id.id
if move.product_uom.id != move.product_id.uom_id.id and move.product_uom.factor > product_uom[move.product_id.id]:
product_uom[move.product_id.id] = move.product_uom.id
product_uom[move.product_id.id] = move.product_id.uom_id
if move.product_uom.id != move.product_id.uom_id.id and move.product_uom.factor > product_uom[move.product_id.id].factor:
product_uom[move.product_id.id] = move.product_uom
pack_obj = self.pool.get("stock.quant.package")
quant_obj = self.pool.get("stock.quant")
@@ -1091,7 +1091,7 @@ class stock_picking(osv.osv):
uom_id = product.uom_id.id
qty_uom = qty
if product_uom.get(key[0]):
uom_id = product_uom[key[0]]
uom_id = product_uom[key[0]].id
qty_uom = uom_obj._compute_qty(cr, uid, product.uom_id.id, qty, uom_id)
vals.append({
'picking_id': picking.id,
@@ -1274,7 +1274,7 @@ class stock_picking(osv.osv):
#2) then, process the remaining part
all_op_processed = True
for ops, product_id, remaining_qty in still_to_do:
all_op_processed = all_op_processed and _create_link_for_product(ops.id, product_id, remaining_qty)
all_op_processed = _create_link_for_product(ops.id, product_id, remaining_qty) and all_op_processed
return (need_rereserve, all_op_processed)
def picking_recompute_remaining_quantities(self, cr, uid, picking, context=None):
@@ -1453,6 +1453,7 @@ class stock_picking(osv.osv):
stock_operation_obj = self.pool.get('stock.pack.operation')
package_obj = self.pool.get('stock.quant.package')
stock_move_obj = self.pool.get('stock.move')
package_id = False
for picking_id in picking_ids:
operation_search_domain = [('picking_id', '=', picking_id), ('result_package_id', '=', False)]
if operation_filter_ids != []:
@@ -1472,7 +1473,7 @@ class stock_picking(osv.osv):
stock_move_obj.check_tracking_product(cr, uid, op.product_id, op.lot_id.id, op.location_id, op.location_dest_id, context=context)
package_id = package_obj.create(cr, uid, {}, context=context)
stock_operation_obj.write(cr, uid, pack_operation_ids, {'result_package_id': package_id}, context=context)
return True
return package_id
def process_product_id_from_ui(self, cr, uid, picking_id, product_id, op_id, increment=1, context=None):
return self.pool.get('stock.pack.operation')._search_and_increment(cr, uid, picking_id, [('product_id', '=', product_id),('id', '=', op_id)], increment=increment, context=context)
+1 -1
View File
@@ -146,7 +146,7 @@ watch your stock valuation, and track production lots (based on serial numbers).
<record id="warehouse0" model="stock.warehouse">
<field model="res.company" name="name" search="[]" use="name"/>
<field name="partner_id" ref="base.main_partner"/>
<field name="code">WH</field>
</record>
@@ -98,7 +98,7 @@ class stock_change_product_qty(osv.osv_memory):
'product_id': data.product_id.id,
'location_id': data.location_id.id,
'lot_id': data.lot_id.id}, context=context)
product = data.product_id.with_context(location=data.location_id.id)
product = data.product_id.with_context(location=data.location_id.id, lot_id= data.lot_id.id)
th_qty = product.qty_available
line_data = {
'inventory_id': inventory_id,
@@ -11,6 +11,10 @@
<field name="product_id" invisible="1"/>
<field name="location_id" groups="stock.group_locations"/>
<field name="lot_id" context="{'search_default_product_id':product_id,'default_product_id':product_id}" groups="stock.group_production_lot"/>
<p groups="stock.group_production_lot" class="oe_grey">
When you select a serial number (lot), the quantity is corrected with respect to
the quantity of that serial number (lot) and not to the total quantity of the product.
</p>
</group>
<footer>
<button name="change_product_qty" string="_Apply" type="object" class="oe_highlight"/>
+12 -1
View File
@@ -86,4 +86,15 @@ class stock_move_scrap(osv.osv_memory):
move_obj.action_scrap(cr, uid, move_ids,
data.product_qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id,
context=context)
return {'type': 'ir.actions.act_window_close'}
if context.get('active_id'):
move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
return {
'view_type': 'form',
'view_mode': 'form',
'res_model': 'stock.picking',
'type': 'ir.actions.act_window',
'res_id': move.picking_id.id,
'context': context
}
else:
return {'type': 'ir.actions.act_window_close'}
+7 -4
View File
@@ -250,7 +250,7 @@ class stock_picking(osv.osv):
invoices += self._invoice_create_line(cr, uid, moves, journal_id, type, context=context)
return invoices
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, origin, context=None):
def _get_invoice_vals(self, cr, uid, key, inv_type, journal_id, move, context=None):
if context is None:
context = {}
partner, currency_id, company_id, user_id = key
@@ -261,7 +261,7 @@ class stock_picking(osv.osv):
account_id = partner.property_account_payable.id
payment_term = partner.property_supplier_payment_term.id or False
return {
'origin': origin,
'origin': move.picking_id.name,
'date_invoice': context.get('date_inv', False),
'user_id': user_id,
'partner_id': partner.id,
@@ -284,12 +284,15 @@ class stock_picking(osv.osv):
partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context)
key = (partner, currency_id, company.id, user_id)
invoice_vals = self._get_invoice_vals(cr, uid, key, inv_type, journal_id, move, context=context)
if key not in invoices:
# Get account and payment terms
invoice_vals = self._get_invoice_vals(cr, uid, key, inv_type, journal_id, origin, context=context)
invoice_id = self._create_invoice_from_picking(cr, uid, move.picking_id, invoice_vals, context=context)
invoices[key] = invoice_id
else:
invoice = invoice_obj.browse(cr, uid, invoices[key], context=context)
invoice.write({'origin': '%s, %s' % (invoice.origin, invoice_vals['origin'],)})
invoice_line_vals = move_obj._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
invoice_line_vals['invoice_id'] = invoices[key]
@@ -309,4 +312,4 @@ class stock_picking(osv.osv):
res.update({'invoice_state': op.picking_id.invoice_state})
if op.linked_move_operation_ids:
res.update({'price_unit': op.linked_move_operation_ids[-1].move_id.price_unit})
return res
return res
+1 -1
View File
@@ -241,7 +241,7 @@ class stock_quant(osv.osv):
'line_id': move_lines,
'period_id': period_id,
'date': move.date,
'ref': move.picking_id and move.picking_id.name}, context=context)
'ref': move.picking_id.name}, context=context)
#def _reconcile_single_negative_quant(self, cr, uid, to_solve_quant, quant, quant_neg, qty, context=None):
# move = self._get_latest_move(cr, uid, to_solve_quant, context=context)
@@ -46,6 +46,9 @@
<xpath expr="//button[@name='do_unreserve']" position="after">
<button name="%(action_stock_invoice_onshipping)d" string="Create Invoice" attrs="{'invisible': ['|',('state','&lt;&gt;','done'),('invoice_state','&lt;&gt;','2binvoiced')]}" type="action" class="oe_highlight" groups="base.group_user"/>
</xpath>
<field name="move_lines" position="attributes">
<attribute name="context">{'default_invoice_state': invoice_state, 'address_in_id': partner_id, 'form_view_ref':'stock.view_move_picking_form', 'tree_view_ref':'stock.view_move_picking_tree', 'default_picking_type_id': picking_type_id,'default_picking_id': active_id}</attribute>
</field>
<xpath expr="//field[@name='move_type']" position="after">
<field name="invoice_state" groups="account.group_account_invoice"/>
</xpath>
@@ -14,7 +14,8 @@
<record id="picking_type_dropship" model="stock.picking.type">
<field name="name">Dropship</field>
<field name="sequence_id" ref="seq_picking_type_dropship"/>
<field name="code">outgoing</field>
<field name="code">incoming</field>
<field name="warehouse_id" eval="False"/>
<field name="default_location_src_id" ref="stock.stock_location_suppliers"/>
<field name="default_location_dest_id" ref="stock.stock_location_customers"/>
</record>
@@ -14,20 +14,20 @@
type: product
uom_id: product.product_uom_unit
uom_po_id: product.product_uom_unit
seller_ids:
seller_ids:
- delay: 1
name: base.res_partner_2
min_qty: 2.0
qty: 10.0
-
Set routes on product to be MTO adn Buy
Set routes on product to be MTO and Buy
-
!python {model: product.product}: |
route_warehouse0_buy = self.pool.get('stock.warehouse').browse(cr, uid, ref('stock.warehouse0')).buy_pull_id.route_id.id
route_warehouse0_mto = self.pool.get('stock.warehouse').browse(cr, uid, ref('stock.warehouse0')).mto_pull_id.route_id.id
self.write(cr, uid, ref('product_mto'), { 'route_ids': [(6, 0, [route_warehouse0_mto,route_warehouse0_buy])]}, context=context )
self.write(cr, uid, ref('product_mto'), { 'route_ids': [(6, 0, [route_warehouse0_mto,route_warehouse0_buy])]}, context=context )
-
Create a sales order with a line of 5 "My Product".
Create a sales order with a line of 5 Units "My Product".
-
!record {model: sale.order, id: sale_order_product_mto}:
partner_id: base.res_partner_3
@@ -40,6 +40,21 @@
Confirm the sale order
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_product_mto}
-
Create another sales order with 2 Dozen of the same product
-
!record {model: sale.order, id: sale_order_product_mto2}:
partner_id: base.res_partner_4
note: Create Sales order
warehouse_id: wh_pps
order_line:
- product_id: product_mto
product_uom_qty: 2.00
product_uom: product.product_uom_dozen
-
Confirm the sale order
-
!workflow {model: sale.order, action: order_confirm, ref: sale_order_product_mto2}
-
I run scheduler.
-
@@ -62,11 +77,21 @@
for procu in self.browse(cr,uid,procu_ids,context=context):
assert procu.state == u'running', 'Procurement with id: %d should be running but is with state : %s!' %(procu.id, procu.state)
# Check that one or more Purchase order
# Check that one purchase order has been created
purchase_ids = [proc.purchase_line_id.order_id for proc in self.browse(cr, uid, procu_ids) if proc.purchase_line_id]
assert len(purchase_ids) > 0, 'No purchase order found !'
# Cancel the main procurement
assert len(purchase_ids) == 1, 'No purchase order found !'
# Check the total quantity on the purchase order which should be in Unit(s)
purchase_line = purchase_ids[0].order_line[0]
assert purchase_line.product_qty == 29.0, 'As we ordered 2 Dozen(s) and 5 Unit(s), total should be 29 Unit(s) and not %s' % (purchase_line.product_qty,)
# Let us cancel the procurement related to the 2nd sales order first and check that the 2 Dozen(s) are subtracted correctly
so2 = self.pool.get('sale.order').browse(cr, uid, ref('sale_order_product_mto2'))
self.cancel(cr, uid, [so2.order_line[0].procurement_ids[0].id], context=context)
assert so2.order_line[0].procurement_ids[0].state == u'cancel', 'Main procurement should be cancelled !'
assert purchase_line.product_qty == 5.0, 'As we ordered 2 Dozen(s) and 5 Unit(s) and cancelled the two Dozen, total should be 5 Unit(s) and not %s' % (purchase_line.product_qty,)
# Cancel the main procurement from the sale order in units
main_procu_id = self.search(cr, uid, [('origin', '=', so.name)])
assert len(main_procu_id) == 1, 'Main procurement not identified !'
self.cancel(cr, uid, main_procu_id, context=context)
@@ -76,6 +101,6 @@
for procu in self.browse(cr, uid, procu_ids, context=context):
assert procu.state == u'cancel', 'Procurement %d should be cancelled but is with a state : %s!' %(procu.id, procu.state)
# Check that the purchase order is well cancelled
# Check that the purchase order is cancelled
for po in self.pool.get('purchase.order').browse(cr, uid, [po.id for po in purchase_ids], context=context):
assert po.state == u'cancel', 'Purchase order %d should be cancelled but is in state : %s!' %(po.id, po.state)
@@ -34,9 +34,12 @@ class stock_invoice_onshipping(osv.osv_memory):
pick = pickings and pickings[0]
src_usage = pick.move_lines[0].location_id.usage
dest_usage = pick.move_lines[0].location_dest_id.usage
pick_purchase = pick.move_lines and pick.move_lines[0].purchase_line_id and pick.move_lines[0].purchase_line_id.order_id.invoice_method == 'picking'
if pick.picking_type_id.code == 'outgoing' and src_usage == 'supplier' and dest_usage == 'customer' and pick_purchase:
return 'purchase'
if src_usage == 'supplier' and dest_usage == 'customer':
pick_purchase = pick.move_lines and pick.move_lines[0].purchase_line_id and pick.move_lines[0].purchase_line_id.order_id.invoice_method == 'picking'
if pick_purchase:
return 'purchase'
else:
return 'sale'
else:
return super(stock_invoice_onshipping, self)._get_journal_type(cr, uid, context=context)

Some files were not shown because too many files have changed in this diff Show More