[MERGE] forward port branch saas-15 up to b0992d082d

This commit is contained in:
Christophe Simonis
2017-04-14 13:32:15 +02:00
117 changed files with 3432 additions and 316 deletions
@@ -795,7 +795,7 @@ class AccountBankStatementLine(models.Model):
or self.statement_id.journal_id.default_debit_account_id.id,
'credit': amount < 0 and -amount or 0.0,
'debit': amount > 0 and amount or 0.0,
'statement_id': self.statement_id.id,
'statement_line_id': self.id,
'currency_id': statement_currency != company_currency and statement_currency.id or (st_line_currency != company_currency and st_line_currency.id or False),
'amount_currency': amount_currency,
}
+7 -3
View File
@@ -504,9 +504,9 @@ class AccountInvoice(models.Model):
else:
account_id = pay_account.id
payment_term_id = p.property_supplier_payment_term_id.id
addr = self.partner_id.address_get(['delivery'])
fiscal_position = self.env['account.fiscal.position'].get_fiscal_position(self.partner_id.id, delivery_id=addr['delivery'])
delivery_partner_id = self.get_delivery_partner_id()
fiscal_position = self.env['account.fiscal.position'].get_fiscal_position(self.partner_id.id, delivery_id=delivery_partner_id)
# If partner has no warning, check its company
if p.invoice_warn == 'no-message' and p.parent_id:
@@ -534,6 +534,10 @@ class AccountInvoice(models.Model):
return {'domain': {'partner_bank_id': [('id', 'in', bank_ids.ids)]}}
return {}
@api.multi
def get_delivery_partner_id(self):
self.ensure_one()
return self.partner_id.address_get(['delivery'])['delivery']
@api.onchange('journal_id')
def _onchange_journal_id(self):
@@ -1050,7 +1054,7 @@ class AccountInvoice(models.Model):
values['invoice_line_ids'] = self._refund_cleanup_lines(invoice.invoice_line_ids)
tax_lines = filter(lambda l: l.manual, invoice.tax_line_ids)
tax_lines = invoice.tax_line_ids
values['tax_line_ids'] = self._refund_cleanup_lines(tax_lines)
if journal_id:
@@ -304,11 +304,13 @@ class account_journal(models.Model):
'default_type': invoice_type,
'type': invoice_type
})
[action] = self.env.ref('account.%s' % action_name).read()
action['context'] = ctx
action['domain'] = self._context.get('use_domain', [])
action['views'] = False
action['view_id'] = False
if action_name in ['action_bank_statement_tree', 'action_view_bank_statement_tree']:
action['views'] = False
action['view_id'] = False
return action
@api.multi
+14 -6
View File
@@ -8,6 +8,7 @@ from odoo.exceptions import RedirectWarning, UserError, ValidationError
from odoo.tools.misc import formatLang
from odoo.tools import float_is_zero, float_compare
from odoo.tools.safe_eval import safe_eval
import odoo.addons.decimal_precision as dp
from lxml import etree
#----------------------------------------------------------
@@ -244,9 +245,9 @@ class AccountMove(models.Model):
journal_id=journal_id)
reversed_moves |= reversed_move
#unreconcile all lines reversed
aml = ac_move.line_ids.filtered(lambda x: x.account_id.reconcile)
aml = ac_move.line_ids.filtered(lambda x: x.account_id.reconcile or x.account_id.internal_type == 'liquidity')
aml.remove_move_reconcile()
#reconcile together the reconciliable aml and their newly created counterpart
#reconcile together the reconciliable and the liquidity aml and their newly created counterpart
for account in [x.account_id for x in aml]:
to_rec = aml.filtered(lambda y: y.account_id == account)
to_rec |= reversed_move.line_ids.filtered(lambda y: y.account_id == account)
@@ -370,7 +371,7 @@ class AccountMoveLine(models.Model):
self.counterpart = ",".join(counterpart)
name = fields.Char(string="Label")
quantity = fields.Float(digits=(16, 2),
quantity = fields.Float(digits=dp.get_precision('Product Unit of Measure'),
help="The optional quantity expressed by this line, eg: number of product sold. The quantity is not a legal requirement but is very useful for some reports.")
product_uom_id = fields.Many2one('product.uom', string='Unit of Measure')
product_id = fields.Many2one('product.product', string='Product')
@@ -811,6 +812,11 @@ class AccountMoveLine(models.Model):
def _get_pair_to_reconcile(self):
#field is either 'amount_residual' or 'amount_residual_currency' (if the reconciled account has a secondary currency set)
field = self[0].account_id.currency_id and 'amount_residual_currency' or 'amount_residual'
#reconciliation on bank accounts are special cases as we don't want to set them as reconciliable
#but we still want to reconcile entries that are reversed together in order to clear those lines
#in the bank reconciliation report.
if not self[0].account_id.reconcile and self[0].account_id.internal_type == 'liquidity':
field = 'balance'
rounding = self[0].company_id.currency_id.rounding
if self[0].currency_id and all([x.amount_currency and x.currency_id == self[0].currency_id for x in self]):
#or if all lines share the same currency
@@ -906,7 +912,7 @@ class AccountMoveLine(models.Model):
raise UserError(_('To reconcile the entries company should be the same for all entries!'))
if len(set(all_accounts)) > 1:
raise UserError(_('Entries are not of the same account!'))
if not all_accounts[0].reconcile:
if not (all_accounts[0].reconcile or all_accounts[0].internal_type == 'liquidity'):
raise UserError(_('The account %s (%s) is not marked as reconciliable !') % (all_accounts[0].name, all_accounts[0].code))
if len(partners) > 1:
raise UserError(_('The partner has to be the same on all lines for receivable and payable accounts!'))
@@ -1500,9 +1506,9 @@ class AccountPartialReconcile(models.Model):
for rec in self:
if not rec.company_id.currency_exchange_journal_id:
raise UserError(_("You should configure the 'Exchange Rate Journal' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
if not self.company_id.income_currency_exchange_account_id.id:
if not rec.company_id.income_currency_exchange_account_id.id:
raise UserError(_("You should configure the 'Gain Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
if not self.company_id.expense_currency_exchange_account_id.id:
if not rec.company_id.expense_currency_exchange_account_id.id:
raise UserError(_("You should configure the 'Loss Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
move = rec.env['account.move'].create(
@@ -1552,6 +1558,8 @@ class AccountPartialReconcile(models.Model):
#amount is the current cash_basis amount minus the one before the reconciliation
amount = line.balance * percentage_after - line.balance * percentage_before
rounded_amt = line.company_id.currency_id.round(amount)
if float_is_zero(rounded_amt, precision_rounding=line.company_id.currency_id.rounding):
continue
if line.tax_line_id and line.tax_line_id.use_cash_basis:
if not newly_created_move:
newly_created_move = self._create_tax_basis_move()
@@ -11,6 +11,7 @@ class ReportPartnerLedger(models.AbstractModel):
def _lines(self, data, partner):
full_account = []
currency = self.env['res.currency']
query_get_data = self.env['account.move.line'].with_context(data['form'].get('used_context', {}))._query_get()
reconcile_clause = "" if data['form']['reconciled'] else ' AND "account_move_line".reconciled = false '
params = [partner.id, tuple(data['computed']['move_state']), tuple(data['computed']['account_ids'])] + query_get_data[2]
@@ -40,6 +41,7 @@ class ReportPartnerLedger(models.AbstractModel):
)
sum += r['debit'] - r['credit']
r['progress'] = sum
r['currency_id'] = currency.browse(r.get('currency_id'))
full_account.append(r)
return full_account
+1 -1
View File
@@ -621,7 +621,7 @@
<field name="act_window_id" ref="action_bank_statement_tree"/>
</record>
<record model="ir.actions.act_window.view" id="action_bank_statement_form_bank">
<field name="sequence" eval="1"/>
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_bank_statement_form"/>
<field name="act_window_id" ref="action_bank_statement_tree"/>
+6 -1
View File
@@ -125,18 +125,23 @@
</table>
</div>
</div>
<div class="row" t-if="len(o.tax_line_ids) > 1">
<!-- DO NOT REMOVE THIS TABLE. MANDATORY IN SOME COUNTRIES -->
<div class="row" t-if="len(o.tax_line_ids) > 0">
<div class="col-xs-6">
<table class="table table-condensed">
<thead>
<tr>
<th>Tax</th>
<th class="text-right">Base</th>
<th class="text-right">Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.tax_line_ids" t-as="t">
<td><span t-field="t.tax_id.description"/></td>
<td class="text-right">
<span t-field="t.base" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
<td class="text-right">
<span t-field="t.amount" t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>
</td>
@@ -36,7 +36,7 @@
<th>Debit</th>
<th>Credit</th>
<th>Balance</th>
<th t-if="amount_currency">Currency</th>
<th t-if="data['form']['amount_currency']">Currency</th>
</tr>
</thead>
<tbody>
@@ -77,8 +77,10 @@
<td class="text-right">
<span t-esc="line['progress']" t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/>
</td>
<td t-if="amount_currency">
<span t-esc="line['amount_currency']" t-options="{'widget': 'monetary', 'display_currency': line['currency_id']}"/>
<td class="text-right" t-if="data['form']['amount_currency']">
<t t-if="line['currency_id']">
<span t-esc="line['amount_currency']" t-options="{'widget': 'monetary', 'display_currency': line['currency_id']}"/>
</t>
</td>
</tr>
</tbody>
@@ -58,7 +58,6 @@ class AccountInvoiceRefund(models.TransientModel):
date = form.date or False
description = form.description or inv.name
refund = inv.refund(form.date_invoice, date, description, inv.journal_id.id)
refund.compute_taxes()
created_inv.append(refund.id)
if mode in ('cancel', 'modify'):
+3 -4
View File
@@ -471,15 +471,14 @@ class AccountAssetDepreciationLine(models.Model):
@api.multi
def create_move(self, post_move=True):
created_moves = self.env['account.move']
prec = self.env['decimal.precision'].precision_get('Account')
for line in self:
category_id = line.asset_id.category_id
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
amount = current_currency.compute(line.amount, company_currency)
sign = (category_id.journal_id.type == 'purchase' or category_id.journal_id.type == 'sale' and 1) or -1
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
prec = self.env['decimal.precision'].precision_get('Account')
move_line_1 = {
'name': asset_name,
'account_id': category_id.account_depreciation_id.id,
@@ -489,7 +488,7 @@ class AccountAssetDepreciationLine(models.Model):
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
@@ -500,7 +499,7 @@ class AccountAssetDepreciationLine(models.Model):
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
'amount_currency': company_currency != current_currency and line.amount or 0.0,
}
move_vals = {
'ref': line.asset_id.code,
+1 -1
View File
@@ -894,7 +894,7 @@ class Lead(models.Model):
'nb_opportunities': 0,
}
opportunities = self.search([('type', '=', 'opportunity'), ('user_id', '=', self._uid)])
opportunities = self.search([('type', '=', 'opportunity'), ('user_id', '=', self._uid), ('activity_date_deadline', '!=', False)])
for opp in opportunities:
# Expected closing
+2 -2
View File
@@ -30,7 +30,7 @@ class EventType(models.Model):
'interval_unit': 'days',
'interval_type': 'before_event',
'template_id': self.env.ref('event.event_reminder')
})]
})] if self.user_has_groups('event.group_email_scheduling') else []
name = fields.Char('Event Category', required=True, translate=True)
# registration
@@ -239,7 +239,7 @@ class EventEvent(models.Model):
if self.event_type_id.use_reply_to:
self.reply_to = self.event_type_id.default_reply_to
if self.event_type_id.use_reply_to:
if self.event_type_id.use_hashtag:
self.twitter_hashtag = self.event_type_id.default_hashtag
if self.event_type_id.use_timezone:
+1 -1
View File
@@ -77,7 +77,7 @@ class EventMailScheduler(models.Model):
if self.interval_type in ['before_event', 'after_event']:
self.done = self.mail_sent
else:
self.done = len(self.mail_registration_ids) == len(self.event_id.registration_ids) and all(filter(lambda line: line.mail_sent, self.mail_registration_ids))
self.done = len(self.mail_registration_ids) == len(self.event_id.registration_ids) and all(mail.mail_sent for mail in self.mail_registration_ids)
@api.one
@api.depends('event_id.state', 'event_id.date_begin', 'interval_type', 'interval_unit', 'interval_nbr')
+10 -2
View File
@@ -172,6 +172,10 @@
<field name="name">Attendees</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="context">{'search_default_event_id': active_id, 'default_event_id': active_id, 'search_default_expected': True}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a new attendee.
</p></field>
</record>
<!-- EVENT.EVENT VIEWS -->
@@ -231,7 +235,11 @@
<group>
<field name="event_type_id" options="{'no_create':True}"/>
<field name="reply_to" string="Contact Email"/>
<field name="twitter_hashtag"/>
<label for="twitter_hashtag"/>
<div>
<span class="oe_inline"># </span>
<field name="twitter_hashtag" nolabel="1" class="oe_inline"/>
</div>
<field name="auto_confirm" groups="base.group_no_one"/>
</group>
<group>
@@ -589,7 +597,7 @@
<field name="scheduled_date"/>
</group>
</group>
<notebook>
<notebook groups="base.group_no_one">
<page string="Registration Mails">
<field name="mail_registration_ids">
<tree string="Registration mail" editable="bottom">
+5 -5
View File
@@ -213,11 +213,11 @@ class FleetVehicle(models.Model):
LogContract = self.env['fleet.vehicle.log.contract']
Cost = self.env['fleet.vehicle.cost']
for record in self:
record.odometer_count = Odometer.search_count([('vehicle_id', '=', self.id)])
record.fuel_logs_count = LogFuel.search_count([('vehicle_id', '=', self.id)])
record.service_count = LogService.search_count([('vehicle_id', '=', self.id)])
record.contract_count = LogContract.search_count([('vehicle_id', '=', self.id)])
record.cost_count = Cost.search_count([('vehicle_id', '=', self.id), ('parent_id', '=', False)])
record.odometer_count = Odometer.search_count([('vehicle_id', '=', record.id)])
record.fuel_logs_count = LogFuel.search_count([('vehicle_id', '=', record.id)])
record.service_count = LogService.search_count([('vehicle_id', '=', record.id)])
record.contract_count = LogContract.search_count([('vehicle_id', '=', record.id)])
record.cost_count = Cost.search_count([('vehicle_id', '=', record.id), ('parent_id', '=', False)])
@api.depends('log_contracts')
def _compute_contract_reminder(self):
+46 -33
View File
@@ -172,19 +172,24 @@ class HrExpense(models.Model):
'''
main function that is called when trying to create the accounting entries related to an expense
'''
move_group_by_sheet = {}
for expense in self:
journal = expense.sheet_id.bank_journal_id if expense.payment_mode == 'company_account' else expense.sheet_id.journal_id
#create the move that will contain the accounting entries
acc_date = expense.sheet_id.accounting_date or expense.date
move = self.env['account.move'].create({
'journal_id': journal.id,
'company_id': self.env.user.company_id.id,
'date': acc_date,
'ref': expense.sheet_id.name,
# force the name to the default value, to avoid an eventual 'default_name' in the context
# to set it to '' which cause no number to be given to the account.move when posted.
'name': '/',
})
if not expense.sheet_id.id in move_group_by_sheet:
move = self.env['account.move'].create({
'journal_id': journal.id,
'company_id': self.env.user.company_id.id,
'date': acc_date,
'ref': expense.sheet_id.name,
# force the name to the default value, to avoid an eventual 'default_name' in the context
# to set it to '' which cause no number to be given to the account.move when posted.
'name': '/',
})
move_group_by_sheet[expense.sheet_id.id] = move
else:
move = move_group_by_sheet[expense.sheet_id.id]
company_currency = expense.company_id.currency_id
diff_currency_p = expense.currency_id != company_currency
#one account.move.line per expense (+taxes..)
@@ -235,38 +240,46 @@ class HrExpense(models.Model):
lines = map(lambda x: (0, 0, expense._prepare_move_line(x)), move_lines)
move.with_context(dont_create_taxes=True).write({'line_ids': lines})
expense.sheet_id.write({'account_move_id': move.id})
move.post()
if expense.payment_mode == 'company_account':
expense.sheet_id.paid_expense_sheets()
for move in move_group_by_sheet.values():
move.post()
return True
@api.multi
def _prepare_move_line_value(self):
self.ensure_one()
if self.account_id:
account = self.account_id
elif self.product_id:
account = self.product_id.product_tmpl_id._get_product_accounts()['expense']
if not account:
raise UserError(
_("No Expense account found for the product %s (or for its category), please configure one.") % (self.product_id.name))
else:
account = self.env['ir.property'].with_context(force_company=self.company_id.id).get('property_account_expense_categ_id', 'product.category')
if not account:
raise UserError(
_('Please configure Default Expense account for Product expense: `property_account_expense_categ_id`.'))
aml_name = self.employee_id.name + ': ' + self.name.split('\n')[0][:64]
move_line = {
'type': 'src',
'name': aml_name,
'price_unit': self.unit_amount,
'quantity': self.quantity,
'price': self.total_amount,
'account_id': account.id,
'product_id': self.product_id.id,
'uom_id': self.product_uom_id.id,
'analytic_account_id': self.analytic_account_id.id,
}
return move_line
@api.multi
def _move_line_get(self):
account_move = []
for expense in self:
if expense.account_id:
account = expense.account_id
elif expense.product_id:
account = expense.product_id.product_tmpl_id._get_product_accounts()['expense']
if not account:
raise UserError(_("No Expense account found for the product %s (or for its category), please configure one.") % (expense.product_id.name))
else:
account = self.env['ir.property'].with_context(force_company=expense.company_id.id).get('property_account_expense_categ_id', 'product.category')
if not account:
raise UserError(_('Please configure Default Expense account for Product expense: `property_account_expense_categ_id`.'))
aml_name = expense.employee_id.name + ': ' + expense.name.split('\n')[0][:64]
move_line = {
'type': 'src',
'name': aml_name,
'price_unit': expense.unit_amount,
'quantity': expense.quantity,
'price': expense.total_amount,
'account_id': account.id,
'product_id': expense.product_id.id,
'uom_id': expense.product_uom_id.id,
'analytic_account_id': expense.analytic_account_id.id,
}
move_line = expense._prepare_move_line_value()
account_move.append(move_line)
# Calculate tax lines and adjust base line
@@ -10,7 +10,7 @@ class HrTimesheetSheet(models.Model):
_inherit = "hr_timesheet_sheet.sheet"
attendances_ids = fields.One2many('hr.attendance', 'sheet_id', 'Attendances')
total_attendance = fields.Integer(string='Total Attendance', compute='_compute_total')
total_attendance = fields.Float(string='Total Attendance', compute='_compute_total')
total_timesheet = fields.Float(string='Total Timesheet', compute="_compute_total")
total_difference = fields.Float(string='Difference', compute="_compute_total")
period_ids = fields.One2many('hr_timesheet_sheet.sheet.day', 'sheet_id', string='Period', readonly=True)
+1 -1
View File
@@ -779,7 +779,7 @@
<record id="chart2500" model="account.account.template">
<field name="code">2500</field>
<field name="reconcile" eval="True"/>
<field name="user_type_id" ref="account.data_account_type_receivable"/>
<field name="user_type_id" ref="account.data_account_type_non_current_assets"/>
<field name="name">Vorsteuer</field>
<field name="chart_template_id" ref="austria_chart_template"/>
</record>
+13 -13
View File
@@ -43,55 +43,55 @@
Resource: res.partner.title
Update partner titles
-->
<record id="res_partner_title_pvt_ltd" model="res.partner.title">
<record id="base.res_partner_title_pvt_ltd" model="res.partner.title">
<field name="name">Corporation</field>
<field name="shortcut">Corp.</field>
</record>
<record id="res_partner_title_ltd" model="res.partner.title">
<record id="base.res_partner_title_ltd" model="res.partner.title">
<field name="name">Limited Company</field>
<field name="shortcut">Ltd.</field>
</record>
<record id="res_partner_title_sal" model="res.partner.title">
<record id="base.res_partner_title_sal" model="res.partner.title">
<field name="name">Sociedad An&#243;nima Laboral</field>
<field name="shortcut">S.A.L.</field>
</record>
<record id="res_partner_title_asoc" model="res.partner.title">
<record id="base.res_partner_title_asoc" model="res.partner.title">
<field name="name">Asociation</field>
<field name="shortcut">Asoc.</field>
</record>
<record id="res_partner_title_gov" model="res.partner.title">
<record id="base.res_partner_title_gov" model="res.partner.title">
<field name="name">Government</field>
<field name="shortcut">Gov.</field>
</record>
<record id="res_partner_title_edu" model="res.partner.title">
<record id="base.res_partner_title_edu" model="res.partner.title">
<field name="name">Educational Institution</field>
<field name="shortcut">Edu.</field>
</record>
<record id="res_partner_title_indprof" model="res.partner.title">
<record id="base.res_partner_title_indprof" model="res.partner.title">
<field name="name">Independant Professional</field>
<field name="shortcut">Ind. Prof.</field>
</record>
<record id="res_partner_title_dra" model="res.partner.title">
<record id="base.res_partner_title_dra" model="res.partner.title">
<field name="name">Doctora</field>
<field name="shortcut">Dra.</field>
</record>
<record id="res_partner_title_msc" model="res.partner.title">
<record id="base.res_partner_title_msc" model="res.partner.title">
<field name="name">Msc.</field>
<field name="shortcut">Msc.</field>
</record>
<record id="res_partner_title_mba" model="res.partner.title">
<record id="base.res_partner_title_mba" model="res.partner.title">
<field name="name">MBA</field>
<field name="shortcut">MBA</field>
</record>
<record id="res_partner_title_lic" model="res.partner.title">
<record id="base.res_partner_title_lic" model="res.partner.title">
<field name="name">Licenciado</field>
<field name="shortcut">Lic.</field>
</record>
<record id="res_partner_title_licda" model="res.partner.title">
<record id="base.res_partner_title_licda" model="res.partner.title">
<field name="name">Licenciada</field>
<field name="shortcut">Licda.</field>
</record>
<record id="res_partner_title_ing" model="res.partner.title">
<record id="base.res_partner_title_ing" model="res.partner.title">
<field name="name">Ingeniero/a</field>
<field name="shortcut">Ing.</field>
</record>
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+31
View File
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Indian - Schedule VI Accounting',
'version': '2.0',
'description': """
Indian Accounting: Chart of Account.
====================================
Indian accounting chart and localization.
Schedule VI chart of account for indian accounting.
Note: The Schedule VI has been revised by MCA and is applicable for all Balance Sheet made after
31st March, 2011. The Format has done away with earlier two options of format of Balance
Sheet, now only Vertical format has been permitted Which is Supported By OpenERP.
""",
'category': 'Localization',
'depends': [
'account',
],
'demo': [],
'data': [
'l10n_in_schedule6_chart.xml',
'l10n_in_schedule6_tax_template.xml',
'account_chart_template.yml',
],
'auto_install': False,
'installable': True,
}
@@ -0,0 +1,3 @@
-
!python {model: account.chart.template, id: indian_chart_template_schedule6}: |
self[0].try_loading_for_current_company()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,842 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Account Tags -->
<record id="st_tag_in_01" model="account.account.tag">
<field name="name">Tax to Pay</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_02" model="account.account.tag">
<field name="name">C Forms</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_03" model="account.account.tag">
<field name="name">C Forms Tax Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_04" model="account.account.tag">
<field name="name">C Forms Tax Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_05" model="account.account.tag">
<field name="name">Excise Duty</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_06" model="account.account.tag">
<field name="name">Excise Duty 12.36%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_07" model="account.account.tag">
<field name="name">Excise Duty Collected on Sales</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_08" model="account.account.tag">
<field name="name">Education Cess 2% Excise Duty Collected on Sales</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_09" model="account.account.tag">
<field name="name">Higher Education Cess 1% Excise Duty Collected on Sales</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_10" model="account.account.tag">
<field name="name">Excise Duty Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_11" model="account.account.tag">
<field name="name">Education Cess 2% Excise Duty Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_12" model="account.account.tag">
<field name="name">Higher Education Cess 1% Excise Duty Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_13" model="account.account.tag">
<field name="name">Sales Tax</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_14" model="account.account.tag">
<field name="name">Sales Tax 4%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_15" model="account.account.tag">
<field name="name">Sales Tax 4% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_16" model="account.account.tag">
<field name="name">Sales Tax 4% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_17" model="account.account.tag">
<field name="name">Sales Tax 12%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_18" model="account.account.tag">
<field name="name">Sales Tax 12% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_19" model="account.account.tag">
<field name="name">Sales Tax 12% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_20" model="account.account.tag">
<field name="name">Sales Tax 15%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_21" model="account.account.tag">
<field name="name">Sales Tax 15% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_22" model="account.account.tag">
<field name="name">Sales Tax 15% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_23" model="account.account.tag">
<field name="name">Service Tax</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_24" model="account.account.tag">
<field name="name">Service Tax 12.36%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_25" model="account.account.tag">
<field name="name">Service Tax Collected on Sales of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_26" model="account.account.tag">
<field name="name">Education Cess 2% Service Tax Collected on Sales of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_27" model="account.account.tag">
<field name="name">Higher Education Cess 1% Service Tax Collected on Sales of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_28" model="account.account.tag">
<field name="name">Service Tax Paid on Purchase of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_29" model="account.account.tag">
<field name="name">Education Cess 2% Service Tax Paid on Purchase of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_30" model="account.account.tag">
<field name="name">Higher Education Cess 1% Service Tax Paid on Purchase of Services</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_31" model="account.account.tag">
<field name="name">VAT</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_32" model="account.account.tag">
<field name="name">VAT 4%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_33" model="account.account.tag">
<field name="name">VAT 4% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_34" model="account.account.tag">
<field name="name">VAT 4% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_35" model="account.account.tag">
<field name="name">VAT 8%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_36" model="account.account.tag">
<field name="name">VAT 8% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_37" model="account.account.tag">
<field name="name">VAT 8% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_38" model="account.account.tag">
<field name="name">VAT 10%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_39" model="account.account.tag">
<field name="name">VAT 10% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_40" model="account.account.tag">
<field name="name">VAT 10% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_41" model="account.account.tag">
<field name="name">VAT 12.5%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_42" model="account.account.tag">
<field name="name">VAT 12.5% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_43" model="account.account.tag">
<field name="name">VAT 12.5% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_44" model="account.account.tag">
<field name="name">Additional VAT 1%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_45" model="account.account.tag">
<field name="name">Additional VAT 1% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_46" model="account.account.tag">
<field name="name">Additional VAT 1% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_47" model="account.account.tag">
<field name="name">Additional VAT 2.5%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_48" model="account.account.tag">
<field name="name">Additional VAT 2.5% Collected on Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_49" model="account.account.tag">
<field name="name">Additional VAT 2.5% Paid on Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_50" model="account.account.tag">
<field name="name">Tax Bases</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_51" model="account.account.tag">
<field name="name">Base C Forms</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_52" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_53" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_54" model="account.account.tag">
<field name="name">Base Excise Duty</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_55" model="account.account.tag">
<field name="name">Base Excise Duty 12.36%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_56" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_57" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_58" model="account.account.tag">
<field name="name">Base Sales Tax</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_59" model="account.account.tag">
<field name="name">Base Sales Tax 4%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_60" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_61" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_62" model="account.account.tag">
<field name="name">Base Sales Tax 12%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_63" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_64" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_65" model="account.account.tag">
<field name="name">Base Sales Tax 15%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_66" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_67" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_68" model="account.account.tag">
<field name="name">Base Service Tax</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_69" model="account.account.tag">
<field name="name">Base Service Tax 12.36%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_70" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_71" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_72" model="account.account.tag">
<field name="name">Base VAT</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_73" model="account.account.tag">
<field name="name">Base VAT 4%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_74" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_75" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_76" model="account.account.tag">
<field name="name">Base VAT 8%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_77" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_78" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_79" model="account.account.tag">
<field name="name">Base VAT 10%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_80" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_81" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_82" model="account.account.tag">
<field name="name">Base VAT 12.5%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_83" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_84" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_85" model="account.account.tag">
<field name="name">Base Additional VAT 1%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_86" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_87" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_88" model="account.account.tag">
<field name="name">Base Additional VAT 2.5%</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_89" model="account.account.tag">
<field name="name">Base of Sale</field>
<field name="applicability">taxes</field>
</record>
<record id="st_tag_in_90" model="account.account.tag">
<field name="name">Base of Purchase</field>
<field name="applicability">taxes</field>
</record>
<!-- Account Tax Templates -->
<record id="input_tax_15" model="account.tax.template">
<field name="name">(schedule6)Input Sales Tax @ 15%</field>
<field name="description">(schedule6)Input Sales Tax @ 15%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">15</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114214"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_21'), ref('st_tag_in_66')])]"/>
</record>
<record id="input_tax_12" model="account.tax.template">
<field name="name">(schedule6)Input Sales Tax @ 12%</field>
<field name="description">(schedule6)Input Sales Tax @ 12%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114214"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_18'), ref('st_tag_in_63')])]"/>
</record>
<record id="input_tax_4" model="account.tax.template">
<field name="name">(schedule6)Input Sales Tax @ 4%</field>
<field name="description">(schedule6)Input Sales Tax @ 4%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">4</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114214"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_15'), ref('st_tag_in_60')])]"/>
</record>
<record id="add_input_vat_1" model="account.tax.template">
<field name="name">(schedule6)Additional Input VAT @ 1%</field>
<field name="description">(schedule6)Additional Input VAT @ 1%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">1</field>
<field name="sequence">15</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_86'), ref('st_tag_in_45')])]"/>
</record>
<record id="input_vat_12" model="account.tax.template">
<field name="name">(schedule6)Input VAT @ 12.5%</field>
<field name="description">(schedule6)Input VAT @ 12.5%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">12.5</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_83'), ref('st_tag_in_42')])]"/>
</record>
<record id="add_input_vat_2" model="account.tax.template">
<field name="name">(schedule6)Additional Input VAT @ 2.5%</field>
<field name="description">(schedule6)Additional Input VAT @ 2.5%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">2.5</field>
<field name="sequence">15</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_89'), ref('st_tag_in_48')])]"/>
</record>
<record id="sale_vat_8" model="account.tax.template">
<field name="name">(schedule6)Input VAT @ 8%</field>
<field name="description">(schedule6)Input VAT @ 8%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">8</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_77'), ref('st_tag_in_36')])]"/>
</record>
<record id="sale_vat_10" model="account.tax.template">
<field name="name">(schedule6)Input VAT @ 10%</field>
<field name="description">(schedule6)Input VAT @ 10%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">10</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_39'), ref('st_tag_in_80')])]"/>
</record>
<record id="sale_tax_12" model="account.tax.template">
<field name="name">(schedule6)Input Tax 12%</field>
<field name="description">(schedule6)Input Tax 12%</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">1</field>
<field name="account_id" ref="c1142111"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_07')])]"/>
</record>
<record id="sale_edu_cess_Excise_Duty_2" model="account.tax.template">
<field name="name">(schedule6)Input Education Cess @ 2% On Excise Duty</field>
<field name="description">(schedule6)Input Education Cess @ 2% On Excise Duty</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.24</field>
<field name="sequence">2</field>
<field name="account_id" ref="c1142112"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_08')])]"/>
</record>
<record id="sale_hedu_cess_Excise_Duty_1" model="account.tax.template">
<field name="name">(schedule6)Input Higher Education Cess @ 1% On Excise Duty</field>
<field name="description">(schedule6)Input Higher Education Cess @ 1% On Excise Duty</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.1224</field>
<field name="sequence">3</field>
<field name="account_id" ref="c1142113"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_09')])]"/>
</record>
<record id="sale_Excise_Duty_12" model="account.tax.template">
<field name="name">(schedule6)Input Excise Duty @ 12.36%</field>
<field name="description">(schedule6)Input Excise Duty @ 12.36%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">group</field>
<field name="amount">0</field>
<field name="sequence">1</field>
<field name="account_id" ref="c1142111"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('sale_tax_12'),ref('sale_edu_cess_Excise_Duty_2'),ref('sale_hedu_cess_Excise_Duty_1')])]"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_56')])]"/>
</record>
<record id="sale_service_tax12" model="account.tax.template">
<field name="name">(schedule6)Input Service Tax 12%</field>
<field name="description">(schedule6)Input Service Tax 12%</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">13</field>
<field name="account_id" ref="c1142121"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_25')])]"/>
</record>
<record id="sale_edu_cess_service_tax_2" model="account.tax.template">
<field name="name">(schedule6)Input Education Cess @ 2% On Service Tax</field>
<field name="description">(schedule6)Input Education Cess @ 2% On Service Tax</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.24</field>
<field name="sequence">14</field>
<field name="account_id" ref="c1142122"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_26')])]"/>
</record>
<record id="sale_high_edu_service_tax_1" model="account.tax.template">
<field name="name">(schedule6)Input Higher Education Cess @ 1% On Service Tax</field>
<field name="description">(schedule6)Input Higher Education Cess @ 1% On Service Tax</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.1224</field>
<field name="sequence">15</field>
<field name="account_id" ref="c1142123"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_27')])]"/>
</record>
<record id="sale_service_tax_12" model="account.tax.template">
<field name="name">(schedule6)Input Service Tax @ 12.36%</field>
<field name="description">(schedule6)Input Service Tax @ 12.36%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">group</field>
<field name="amount">12</field>
<field name="include_base_amount">True</field>
<field name="sequence">8</field>
<field name="account_id" ref="c1142121"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('sale_service_tax12'),ref('sale_edu_cess_service_tax_2'),ref('sale_high_edu_service_tax_1')])]"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_70')])]"/>
</record>
<record id="input_vat_4" model="account.tax.template">
<field name="name">(schedule6)Input VAT @ 4%</field>
<field name="description">(schedule6)Input VAT @ 4%</field>
<field name="type_tax_use">sale</field>
<field name="amount_type">percent</field>
<field name="amount">4</field>
<field name="sequence">10</field>
<field name="account_id" ref="c114215"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_33'), ref('st_tag_in_74')])]"/>
</record>
<!--output purchase tax-->
<record id="output_tax_15" model="account.tax.template">
<field name="name">(schedule6)Output Purchase Tax @ 15%</field>
<field name="description">(schedule6)Output Purchase Tax @ 15%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">15</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121610"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_22'), ref('st_tag_in_67')])]"/>
</record>
<record id="output_tax_12" model="account.tax.template">
<field name="name">(schedule6)Output Purchase Tax @ 12%</field>
<field name="description">(schedule6)Output Purchase Tax @ 12%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121610"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6, 0, [ref('st_tag_in_19'), ref('st_tag_in_64')])]"/>
</record>
<record id="output_tax_4" model="account.tax.template">
<field name="name">(schedule6)Output Purchase Tax @ 4%</field>
<field name="description">(schedule6)Output Purchase Tax @ 4%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">4</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121610"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_61'), ref('st_tag_in_16')])]"/>
</record>
<record id="add_output_vat_1" model="account.tax.template">
<field name="name">(schedule6)Additional Output VAT @ 1%</field>
<field name="description">(schedule6)Additional Output VAT @ 1%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">1</field>
<field name="sequence">15</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_87'), ref('st_tag_in_46')])]"/>
</record>
<record id="output_vat_12" model="account.tax.template">
<field name="name">(schedule6)Output VAT @ 12.5%</field>
<field name="description">(schedule6)Output VAT @ 12.5%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">12.5</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_43'), ref('st_tag_in_84')])]"/>
</record>
<record id="add_output_vat_2" model="account.tax.template">
<field name="name">(schedule6)Additional Output VAT @ 2.5%</field>
<field name="description">(schedule6)Additional Output VAT @ 2.5%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">2.5</field>
<field name="sequence">15</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_90'), ref('st_tag_in_49')])]"/>
</record>
<record id="purchase_vat_8" model="account.tax.template">
<field name="name">(schedule6)Output VAT @ 8%</field>
<field name="description">(schedule6)Output VAT @ 8%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">8</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_78'), ref('st_tag_in_37')])]"/>
</record>
<record id="purchase_vat_10" model="account.tax.template">
<field name="name">(schedule6)Output VAT @ 10%</field>
<field name="description">(schedule6)Output VAT @ 10%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">10</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_81'), ref('st_tag_in_40')])]"/>
</record>
<record id="purchase_edu_cess_12" model="account.tax.template">
<field name="name">(schedule6)Output Tax 12%</field>
<field name="description">(schedule6)Output Tax 12%</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">2</field>
<field name="account_id" ref="c1216121"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_10')])]"/>
</record>
<record id="purchase_edu_cess_Excise_Duty_2" model="account.tax.template">
<field name="name">(schedule6)Output Education Cess @ 2% Excise Duty</field>
<field name="description">(schedule6)Output Education Cess @ 2% Excise Duty</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.24</field>
<field name="sequence">3</field>
<field name="account_id" ref="c1216122"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_11')])]"/>
</record>
<record id="purchase_hedu_cess_Excise_Duty_1" model="account.tax.template">
<field name="name">(schedule6)Output Higher Education Cess @ 1% Excise Duty</field>
<field name="description">(schedule6)Output Higher Education Cess @ 1% Excise Duty</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.1224</field>
<field name="sequence">4</field>
<field name="account_id" ref="c1216123"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_12')])]"/>
</record>
<record id="purchase_Excise_Duty_12" model="account.tax.template">
<field name="name">(schedule6)Output Excise Duty @ 12.36%</field>
<field name="description">(schedule6)Output Excise Duty @ 12.36%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">group</field>
<field name="amount">12</field>
<field name="include_base_amount">True</field>
<field name="sequence">1</field>
<field name="account_id" ref="c1216121"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('purchase_edu_cess_12'),ref('purchase_edu_cess_Excise_Duty_2'),ref('purchase_hedu_cess_Excise_Duty_1')])]"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_57')])]"/>
</record>
<record id="purchase_edu_service_tax12" model="account.tax.template">
<field name="name">(schedule6)Output Service Tax 12%</field>
<field name="description">(schedule6)Output Service Tax 12%</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">12</field>
<field name="sequence">9</field>
<field name="account_id" ref="c1216131"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_28')])]"/>
</record>
<record id="purchase_edu_cess_service_tax_2" model="account.tax.template">
<field name="name">(schedule6)Output Education Cess @ 2% On Service Tax</field>
<field name="description">(schedule6)Output Education Cess @ 2% On Service Tax</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.24</field>
<field name="sequence">10</field>
<field name="account_id" ref="c1216132"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_29')])]"/>
</record>
<record id="purchase_high_edu_service_tax_1" model="account.tax.template">
<field name="name">(schedule6)Output Higher Education Cess @ 1% On Service Tax</field>
<field name="description">(schedule6)Output Higher Education Cess @ 1% On Service Tax</field>
<field name="type_tax_use">none</field>
<field name="amount_type">percent</field>
<field name="amount">0.1224</field>
<field name="sequence">11</field>
<field name="account_id" ref="c1216133"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_30')])]"/>
</record>
<record id="st_purchase_service_tax_12" model="account.tax.template">
<field name="name">(schedule6)Output Service Tax @ 12.36%</field>
<field name="description">(schedule6)Output Service Tax @ 12.36%</field>
<field name="type_tax_use">purchase</field>
<field name="include_base_amount">True</field>
<field name="amount_type">group</field>
<field name="amount">12</field>
<field name="sequence">8</field>
<field name="account_id" ref="c1216131"/>
<field name="children_tax_ids" eval="[(6, 0, [ref('purchase_edu_service_tax12'),ref('purchase_edu_cess_service_tax_2'),ref('purchase_high_edu_service_tax_1')])]"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_71')])]"/>
</record>
<record id="output_vat_4" model="account.tax.template">
<field name="name">(schedule6)Output VAT @ 4%</field>
<field name="description">(schedule6)Output VAT @ 4%</field>
<field name="type_tax_use">purchase</field>
<field name="amount_type">percent</field>
<field name="amount">4</field>
<field name="sequence">10</field>
<field name="account_id" ref="c121611"/>
<field name="chart_template_id" ref="indian_chart_template_schedule6"/>
<field name="tag_ids" eval="[(6,0,[ref('st_tag_in_34'), ref('st_tag_in_75')])]"/>
</record>
</data>
</openerp>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+12 -11
View File
@@ -1696,9 +1696,10 @@ class MailThread(models.AbstractModel):
return self._message_post_process_attachments(attachments, attachment_ids, {'model': attach_model, 'res_id': attach_res_id})
def _message_post_process_attachments(self, attachments, attachment_ids, message_data):
IrAttachment, parameter_attachments = self.env['ir.attachment'], self.env['ir.attachment']
IrAttachment = self.env['ir.attachment']
m2m_attachment_ids = []
cid_mapping = {}
fname_mapping = {}
if attachment_ids:
filtered_attachment_ids = self.env['ir.attachment'].sudo().search([
('res_model', '=', 'mail.compose.message'),
@@ -1714,9 +1715,7 @@ class MailThread(models.AbstractModel):
name, content = attachment
elif len(attachment) == 3:
name, content, info = attachment
if info and info.get('cid'):
cid = info['cid']
cid_mapping[cid] = name
cid = info and info.get('cid')
else:
continue
if isinstance(content, unicode):
@@ -1724,13 +1723,16 @@ class MailThread(models.AbstractModel):
data_attach = {
'name': name,
'datas': base64.b64encode(str(content)),
'datas_fname': cid or name,
'datas_fname': name,
'description': name,
'res_model': message_data['model'],
'res_id': message_data['res_id'],
}
parameter_attachments |= IrAttachment.create(data_attach)
m2m_attachment_ids += [(4, attach.id) for attach in parameter_attachments]
new_attachment = IrAttachment.create(data_attach)
m2m_attachment_ids.append((4, new_attachment.id))
if cid:
cid_mapping[cid] = new_attachment
fname_mapping[name] = new_attachment
if cid_mapping and message_data.get('body'):
root = lxml.html.fromstring(tools.ustr(message_data['body']))
@@ -1738,12 +1740,11 @@ class MailThread(models.AbstractModel):
for node in root.iter('img'):
if node.get('src', '').startswith('cid:'):
cid = node.get('src').split('cid:')[1]
fname = cid_mapping.get(cid, node.get('data-filename', ''))
attachment = parameter_attachments.filtered(lambda attachment: attachment.datas_fname == cid)
attachment = cid_mapping.get(cid)
if not attachment:
attachment = parameter_attachments.filtered(lambda attachment: attachment.datas_fname == fname)
attachment = fname_mapping.get(node.get('data-filename'), '')
if attachment:
node.set('src', '/web/image/%s' % attachment.ids[0])
node.set('src', '/web/image/%s' % attachment.id)
postprocessed = True
if postprocessed:
body = lxml.html.tostring(root, pretty_print=False, encoding='UTF-8')
@@ -312,7 +312,7 @@
<field name="owner_user_id" string="Owner"/>
</group>
<group>
<field name="maintenance_team_id"/>
<field name="maintenance_team_id" attrs="{'required': [('period', '!=', 0)]}"/>
<field name="technician_user_id"/>
<field name="assign_date" groups="base.group_no_one"/>
<field name="scrap_date" groups="base.group_no_one"/>
+1 -2
View File
@@ -7,8 +7,7 @@ import werkzeug.urls
from odoo import api, fields, models, tools
URL_REGEX = r'(\bhref=[\'"]([^\'"]+)[\'"])'
from openerp.addons.link_tracker.models.link_tracker import URL_REGEX
class MailMail(models.Model):
+6 -1
View File
@@ -44,7 +44,12 @@ class ProductProduct(models.Model):
read_group_res = self.env['mrp.bom'].read_group([('product_id', 'in', self.ids)], ['product_id'], ['product_id'])
mapped_data = dict([(data['product_id'][0], data['product_id_count']) for data in read_group_res])
for product in self:
product.bom_count = mapped_data.get(product.id, 0)
if product.product_tmpl_id.product_variant_count == 1:
bom_count = mapped_data.get(product.id, product.product_tmpl_id.bom_count)
else:
bom_count = mapped_data.get(product.id, 0)
product.bom_count = bom_count
def _compute_mo_count(self):
read_group_res = self.env['mrp.production'].read_group([('product_id', 'in', self.ids)], ['product_id'], ['product_id'])
+10 -1
View File
@@ -33,7 +33,7 @@ class StockMoveLots(models.Model):
def _check_lot_id(self):
if self.move_id.product_id.tracking == 'serial':
lots = set([])
for move_lot in self.move_id.move_lot_ids.filtered(lambda r: not r.lot_produced_id):
for move_lot in self.move_id.active_move_lot_ids.filtered(lambda r: not r.lot_produced_id and r.lot_id):
if move_lot.lot_id in lots:
raise exceptions.UserError(_('You cannot use the same serial number in two different lines.'))
if float_compare(move_lot.quantity_done, 1.0, precision_rounding=move_lot.product_id.uom_id.rounding) == 1:
@@ -59,6 +59,15 @@ class StockMoveLots(models.Model):
self.quantity_done = self.quantity_done - 1
return self.move_id.split_move_lot()
@api.multi
def write(self, vals):
if 'lot_id' in vals:
for movelot in self:
movelot.move_id.production_id.move_raw_ids.mapped('move_lot_ids')\
.filtered(lambda r: r.done_wo and not r.done_move and r.lot_produced_id == movelot.lot_id)\
.write({'lot_produced_id': vals['lot_id']})
return super(StockMoveLots, self).write(vals)
class StockMove(models.Model):
_inherit = 'stock.move'
+4 -1
View File
@@ -520,7 +520,10 @@ class RepairLine(models.Model):
if not self.product_id or not self.product_uom_qty:
return
if self.product_id:
self.name = self.product_id.display_name
if partner:
self.name = self.product_id.with_context(lang=partner.lang).display_name
else:
self.name = self.product_id.display_name
self.product_uom = self.product_id.uom_id.id
if self.type != 'remove':
if partner and self.product_id:
@@ -5,7 +5,7 @@
string="Quotation / Order"
id="action_report_mrp_repair_order"
model="mrp.repair"
name="mrp_repair.report_mrprepairorder"
name="mrp_repair.report_mrprepairorder2"
file="mrp_repair.report_mrprepairorder"
report_type="qweb-pdf"
/>
@@ -2,9 +2,9 @@
<odoo>
<data>
<template id="report_mrprepairorder">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="report.external_layout">
<t t-set="o" t-value="o.with_context({'lang': o.partner_id.lang})" />
<div class="page">
<div class="oe_structure"/>
@@ -156,6 +156,13 @@
</div>
</t>
</t>
</template>
<template id="report_mrprepairorder2">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="doc">
<t t-call="mrp_repair.report_mrprepairorder" t-lang="doc.partner_id.lang"/>
</t>
</t>
</template>
</data>
@@ -150,7 +150,7 @@ class AuthorizeAPI():
etree.SubElement(root, "transId").text = transaction_id
customer = etree.SubElement(root, "customer")
etree.SubElement(customer, "merchantCustomerId").text = 'ODOO-%s-%s' % (partner.id, uuid4().hex[:8])
etree.SubElement(customer, "email").text = partner.email
etree.SubElement(customer, "email").text = partner.email or ''
response = self._authorize_request(root)
res = dict()
res['profile_id'] = response.find('customerProfileId').text
+10 -4
View File
@@ -32,16 +32,22 @@ class PaypalController(http.Controller):
:param response str: text response, structured in the following way:
STATUS\nkey1=value1\nkey2=value2...\n
or STATUS\nError message...\n
:rtype tuple(str, dict)
:return: tuple containing the STATUS str and the key/value pairs
parsed as a dict
"""
lines = filter(None, response.split('\n'))
status = lines.pop(0)
pdt_post = dict(line.split('=', 1) for line in lines)
# html unescape
for post in pdt_post:
pdt_post[post] = urllib.unquote_plus(pdt_post[post]).decode('utf8')
pdt_post = {}
for line in lines:
split = line.split('=', 1)
if len(split) == 2:
pdt_post[split[0]] = urllib.unquote_plus(split[1]).decode('utf8')
else:
_logger.warning('Paypal: error processing pdt response: %s', line)
return status, pdt_post
def paypal_validate_data(self, **post):
+4 -1
View File
@@ -14,7 +14,10 @@ class PosController(http.Controller):
@http.route('/pos/web', type='http', auth='user')
def pos_web(self, debug=False, **k):
# if user not logged in, log him in
pos_sessions = request.env['pos.session'].search([('state', '=', 'opened'), ('user_id', '=', request.session.uid)])
pos_sessions = request.env['pos.session'].search([
('state', '=', 'opened'),
('user_id', '=', request.session.uid),
('name', 'not like', '(RESCUE FOR')])
if not pos_sessions:
return werkzeug.utils.redirect('/web#action=point_of_sale.action_client_pos_menu')
pos_sessions.login()
+10 -6
View File
@@ -31,7 +31,7 @@ class PosConfig(models.Model):
def _default_sale_journal(self):
journal = self.env.ref('point_of_sale.pos_sale_journal', raise_if_not_found=False)
if journal and journal.company_id == self.env.user.company_id:
if journal and journal.sudo().company_id == self.env.user.company_id:
return journal
return self._default_invoice_journal()
@@ -146,9 +146,12 @@ class PosConfig(models.Model):
@api.depends('session_ids')
def _compute_current_session(self):
for pos_config in self:
session = pos_config.session_ids.filtered(lambda r: r.user_id.id == self.env.uid and not r.state == 'closed')
pos_config.current_session_id = session
pos_config.current_session_state = session.state
session = pos_config.session_ids.filtered(lambda r: r.user_id.id == self.env.uid and \
not r.state == 'closed' and \
'(RESCUE FOR' not in r.name)
# sessions ordered by id desc
pos_config.current_session_id = session and session[0].id or False
pos_config.current_session_state = session and session[0].state or False
@api.depends('session_ids')
def _compute_last_session(self):
@@ -168,7 +171,8 @@ class PosConfig(models.Model):
@api.depends('session_ids')
def _compute_current_session_user(self):
for pos_config in self:
pos_config.pos_session_username = pos_config.session_ids.filtered(lambda s: s.state == 'opened').user_id.name
session = pos_config.session_ids.filtered(lambda s: s.state == 'opened' and '(RESCUE FOR' not in s.name)
pos_config.pos_session_username = session and session[0].user_id.name or False
@api.constrains('company_id', 'stock_location_id')
def _check_company_location(self):
@@ -216,7 +220,7 @@ class PosConfig(models.Model):
@api.model
def create(self, values):
IrSequence = self.env['ir.sequence']
IrSequence = self.env['ir.sequence'].sudo()
val = {
'name': _('POS Order %s') % values['name'],
'padding': 4,
+35 -11
View File
@@ -66,11 +66,18 @@ class PosOrder(models.Model):
closed_session.id,
order['name'],
order['amount_total'])
rescue_session = PosSession.search([
('name', 'like', '(RESCUE FOR %(session)s)' % {'session': closed_session.name}),
('state', 'not in', ('closed', 'closing_control')),
], limit=1)
if rescue_session:
_logger.warning('reusing recovery session %s for saving order %s', rescue_session.name, order['name'])
return rescue_session
_logger.warning('attempting to create recovery session for saving order %s', order['name'])
new_session = PosSession.create({
'config_id': closed_session.config_id.id,
'name': _('(RESCUE FOR %(session)s)') % {'session': closed_session.name},
'rescue': True, # avoid conflict with live sessions
'name': '(RESCUE FOR %(session)s)' % {'session': closed_session.name},
})
# bypass opening_control (necessary when using cash control)
new_session.action_pos_session_open()
@@ -347,7 +354,12 @@ class PosOrder(models.Model):
name = fields.Char(string='Order Ref', required=True, readonly=True, copy=False, default='/')
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, default=lambda self: self.env.user.company_id)
date_order = fields.Datetime(string='Order Date', readonly=True, index=True, default=fields.Datetime.now)
user_id = fields.Many2one('res.users', string='Salesman', help="Person who uses the cash register. It can be a reliever, a student or an interim employee.", default=lambda self: self.env.uid)
user_id = fields.Many2one(
comodel_name='res.users', string='Salesman',
help="Person who uses the cash register. It can be a reliever, a student or an interim employee.",
default=lambda self: self.env.uid,
states={'done': [('readonly', True)], 'invoiced': [('readonly', True)]},
)
amount_tax = fields.Float(compute='_compute_amount_all', string='Taxes', digits=0)
amount_total = fields.Float(compute='_compute_amount_all', string='Total', digits=0)
amount_paid = fields.Float(compute='_compute_amount_all', string='Paid', states={'draft': [('readonly', False)]}, readonly=True, digits=0)
@@ -372,12 +384,22 @@ class PosOrder(models.Model):
account_move = fields.Many2one('account.move', string='Journal Entry', readonly=True, copy=False)
picking_id = fields.Many2one('stock.picking', string='Picking', readonly=True, copy=False)
picking_type_id = fields.Many2one('stock.picking.type', related='session_id.config_id.picking_type_id', string="Operation Type")
location_id = fields.Many2one('stock.location', related='session_id.config_id.stock_location_id', string="Location", store=True)
location_id = fields.Many2one(
comodel_name='stock.location',
related='session_id.config_id.stock_location_id',
string="Location", store=True,
readonly=True,
)
note = fields.Text(string='Internal Notes')
nb_print = fields.Integer(string='Number of Print', readonly=True, copy=False, default=0)
pos_reference = fields.Char(string='Receipt Ref', readonly=True, copy=False)
sale_journal = fields.Many2one('account.journal', related='session_id.config_id.journal_id', string='Sales Journal', store=True, readonly=True)
fiscal_position_id = fields.Many2one('account.fiscal.position', string='Fiscal Position', default=lambda self: self._default_session().config_id.default_fiscal_position_id)
fiscal_position_id = fields.Many2one(
comodel_name='account.fiscal.position', string='Fiscal Position',
default=lambda self: self._default_session().config_id.default_fiscal_position_id,
readonly=True,
states={'draft': [('readonly', False)]},
)
@api.depends('statement_ids', 'lines.price_subtotal_incl', 'lines.discount')
def _compute_amount_all(self):
@@ -553,6 +575,8 @@ class PosOrder(models.Model):
Move = self.env['stock.move']
StockWarehouse = self.env['stock.warehouse']
for order in self:
if not order.lines.filtered(lambda l: l.product_id.type in ['product', 'consu']):
continue
address = order.partner_id.address_get(['delivery']) or {}
picking_type = order.picking_type_id
return_pick_type = order.picking_type_id.return_picking_type_id or order.picking_type_id
@@ -582,7 +606,7 @@ class PosOrder(models.Model):
'location_id': location_id,
'location_dest_id': destination_id,
}
pos_qty = any([x.qty >= 0 for x in order.lines])
pos_qty = any([x.qty > 0 for x in order.lines])
if pos_qty:
order_picking = Picking.create(picking_vals.copy())
order_picking.message_post(body=message)
@@ -620,8 +644,8 @@ class PosOrder(models.Model):
# when the pos.config has no picking_type_id set only the moves will be created
if moves and not return_picking and not order_picking:
moves.action_confirm()
moves.force_assign()
moves.action_assign()
moves.filtered(lambda m: m.state in ['confirmed', 'waiting']).force_assign()
moves.filtered(lambda m: m.product_id.tracking == 'none').action_done()
return True
@@ -629,7 +653,7 @@ class PosOrder(models.Model):
def _force_picking_done(self, picking):
"""Force picking in order to be set as done."""
self.ensure_one()
picking.action_confirm()
picking.action_assign()
picking.force_assign()
wrong_lots = self.set_pack_operation_lot(picking)
if not wrong_lots:
@@ -766,9 +790,9 @@ class PosOrderLine(models.Model):
def _order_line_fields(self, line, session_id=None):
if line and 'name' not in line[2]:
if session_id:
session = self.env['pos.session'].browse(session_id).exists() if session_id else None
if session and session.config_id.sequence_line_id:
# set name based on the sequence specified on the config
session = self.env['pos.session'].browse(session_id)
line[2]['name'] = session.config_id.sequence_line_id._next()
else:
# fallback on any pos.order.line sequence
+10 -2
View File
@@ -130,12 +130,20 @@ class PosSession(models.Model):
@api.constrains('user_id', 'state')
def _check_unicity(self):
# open if there is no session in 'opening_control', 'opened', 'closing_control' for one user
if self.search_count([('state', 'not in', ('closed', 'closing_control')), ('user_id', '=', self.user_id.id)]) > 1:
if self.search_count([
('state', 'not in', ('closed', 'closing_control')),
('user_id', '=', self.user_id.id),
('name', 'not like', 'RESCUE FOR'),
]) > 1:
raise ValidationError(_("You cannot create two active sessions with the same responsible!"))
@api.constrains('config_id')
def _check_pos_config(self):
if self.search_count([('state', '!=', 'closed'), ('config_id', '=', self.config_id.id)]) > 1:
if self.search_count([
('state', '!=', 'closed'),
('config_id', '=', self.config_id.id),
('name', 'not like', 'RESCUE FOR'),
]) > 1:
raise ValidationError(_("You cannot create two active sessions related to the same point of sale!"))
@api.model
@@ -12,7 +12,7 @@ class PosOrderReport(models.Model):
date = fields.Datetime(string='Date Order', readonly=True)
order_id = fields.Many2one('pos.order', string='Order', readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True)
partner_id = fields.Many2one('res.partner', string='Customer', readonly=True)
product_id = fields.Many2one('product.product', string='Product', readonly=True)
product_tmpl_id = fields.Many2one('product.template', string='Product Template', readonly=True)
state = fields.Selection(
+2 -1
View File
@@ -11,6 +11,7 @@ var CrashManager = require('web.CrashManager');
var _t = core._t;
var _lt = core._lt;
var QWeb = core.qweb;
/* -------- The Order Selector -------- */
@@ -821,7 +822,7 @@ var Chrome = PosBaseWidget.extend({
'widget': HeaderButtonWidget,
'append': '.pos-rightheader',
'args': {
label: _t('Close'),
label: _lt('Close'),
action: function(){
var self = this;
if (!this.confirmed) {
+3 -1
View File
@@ -1437,7 +1437,9 @@ exports.Orderline = Backbone.Model.extend({
this.trigger('change',this);
},
get_unit_price: function(){
return round_di(this.price || 0, this.pos.dp['Product Price'])
var digits = this.pos.dp['Product Price'];
// round and truncate to mimic _sybmbol_set behavior
return parseFloat(round_di(this.price || 0, digits).toFixed(digits));
},
get_unit_display_price: function(){
if (this.pos.config.iface_tax_included) {
+13 -2
View File
@@ -1360,6 +1360,16 @@ var ClientListScreenWidget = ScreenWidget.extend({
contents.append($(QWeb.render('ClientDetailsEdit',{widget:this,partner:partner})));
this.toggle_save_button();
// Browsers attempt to scroll invisible input elements
// into view (eg. when hidden behind keyboard). They don't
// seem to take into account that some elements are not
// scrollable.
contents.find('input').blur(function() {
setTimeout(function() {
self.$('.window').scrollTop(0);
}, 0);
});
contents.find('.image-uploader').on('change',function(event){
self.load_image_file(event.target.files[0],function(res){
if (res) {
@@ -1409,7 +1419,9 @@ var ReceiptScreenWidget = ScreenWidget.extend({
this.render_change();
this.render_receipt();
this.handle_auto_print();
},
handle_auto_print: function() {
if (this.should_auto_print()) {
this.print();
if (this.should_close_immediately()){
@@ -1418,7 +1430,6 @@ var ReceiptScreenWidget = ScreenWidget.extend({
} else {
this.lock_screen(false);
}
},
should_auto_print: function() {
return this.pos.config.iface_print_auto && !this.pos.get_order()._printed;
+4
View File
@@ -10,12 +10,16 @@ class TestPointOfSaleCommon(common.TransactionCase):
self.AccountBankStatementLine = self.env['account.bank.statement.line']
self.PosMakePayment = self.env['pos.make.payment']
self.PosOrder = self.env['pos.order']
self.PosSession = self.env['pos.session']
self.company_id = self.ref('base.main_company')
self.product3 = self.env.ref('product.product_product_3')
self.product4 = self.env.ref('product.product_product_4')
self.partner1 = self.env.ref('base.res_partner_1')
self.partner4 = self.env.ref('base.res_partner_4')
self.pos_config = self.env.ref('point_of_sale.pos_config_main')
self.carotte = self.env.ref('point_of_sale.carotte')
self.courgette = self.env.ref('point_of_sale.courgette')
self.onions = self.env.ref('point_of_sale.Onions')
# create a new session
self.pos_order_session0 = self.env['pos.session'].create({
@@ -4,8 +4,8 @@ import time
import os
import odoo
from odoo import tools, report as odoo_report
from odoo.tools import float_compare, test_reports
from odoo import fields, tools, report as odoo_report
from odoo.tools import float_compare, mute_logger, test_reports
from odoo.addons.point_of_sale.tests.common import TestPointOfSaleCommon
@@ -451,3 +451,138 @@ class TestPointOfSaleFlow(TestPointOfSaleCommon):
# I confirm the bank statement using Confirm button
self.AccountBankStatement.button_confirm_bank()
def test_create_from_ui(self):
"""
Simulation of sales coming from the interface, even after closing the session
"""
# I click on create a new session button
self.pos_config.open_session_cb()
current_session = self.pos_config.current_session_id
num_starting_orders = len(current_session.order_ids)
carrot_order = {'data':
{'amount_paid': 0.9,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 0.9,
'creation_date': fields.Datetime.now(),
'fiscal_position_id': False,
'lines': [[0,
0,
{'discount': 0,
'id': 42,
'pack_lot_ids': [],
'price_unit': 0.9,
'product_id': self.carotte.id,
'qty': 1,
'tax_ids': []}]],
'name': 'Order 00042-003-0014',
'partner_id': False,
'pos_session_id': current_session.id,
'sequence_number': 2,
'statement_ids': [[0,
0,
{'account_id': self.env.user.partner_id.property_account_receivable_id.id,
'amount': 0.9,
'journal_id': self.pos_config.journal_ids[0].id,
'name': fields.Datetime.now(),
'statement_id': current_session.statement_ids[0].id}]],
'uid': '00042-003-0014',
'user_id': self.env.uid},
'id': '00042-003-0014',
'to_invoice': False}
zucchini_order = {'data':
{'amount_paid': 1.2,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 1.1,
'creation_date': fields.Datetime.now(),
'fiscal_position_id': False,
'lines': [[0,
0,
{'discount': 0,
'id': 3,
'pack_lot_ids': [],
'price_unit': 1.2,
'product_id': self.courgette.id,
'qty': 1,
'tax_ids': []}]],
'name': 'Order 00043-003-0014',
'partner_id': False,
'pos_session_id': current_session.id,
'sequence_number': self.pos_config.journal_id.id,
'statement_ids': [[0,
0,
{'account_id': self.env.user.partner_id.property_account_receivable_id.id,
'amount': 1.2,
'journal_id': self.pos_config.journal_ids[0].id,
'name': fields.Datetime.now(),
'statement_id': current_session.statement_ids[0].id}]],
'uid': '00043-003-0014',
'user_id': self.env.uid},
'id': '00043-003-0014',
'to_invoice': False}
onions_order = {'data':
{'amount_paid': 1.28,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 1.28,
'creation_date': fields.Datetime.now(),
'fiscal_position_id': False,
'lines': [[0,
0,
{'discount': 0,
'id': 3,
'pack_lot_ids': [],
'price_unit': 1.28,
'product_id': self.onions.id,
'qty': 1,
'tax_ids': [[6, False, self.onions.taxes_id.ids]]}]],
'name': 'Order 00044-003-0014',
'partner_id': False,
'pos_session_id': current_session.id,
'sequence_number': self.pos_config.journal_id.id,
'statement_ids': [[0,
0,
{'account_id': self.env.user.partner_id.property_account_receivable_id.id,
'amount': 1.28,
'journal_id': self.pos_config.journal_ids[0].id,
'name': fields.Datetime.now(),
'statement_id': current_session.statement_ids[0].id}]],
'uid': '00044-003-0014',
'user_id': self.env.uid},
'id': '00044-003-0014',
'to_invoice': False}
# I create an order on an open session
self.PosOrder.create_from_ui([carrot_order])
self.assertEqual(num_starting_orders + 1, len(current_session.order_ids), "Submitted order not encoded")
# I resubmit the same order
self.PosOrder.create_from_ui([carrot_order])
self.assertEqual(num_starting_orders + 1, len(current_session.order_ids), "Resubmitted order was not skipped")
# I close the session
current_session.action_pos_session_closing_control()
self.assertEqual(current_session.state, 'closed', "Session was not properly closed")
self.assertFalse(self.pos_config.current_session_id, "Current session not properly recomputed")
# I keep selling after the session is closed
with mute_logger('odoo.addons.point_of_sale.models.pos_order'):
self.PosOrder.create_from_ui([zucchini_order, onions_order])
rescue_session = self.PosSession.search([
('config_id', '=', self.pos_config.id),
('state', '=', 'opened'),
])
self.assertEqual(len(rescue_session), 1, "One (and only one) rescue session should be created for orphan orders")
self.assertIn("(RESCUE FOR %s)" % current_session.name, rescue_session.name, "Rescue session is not linked to the previous one")
self.assertEqual(len(rescue_session.order_ids), 2, "Rescue session does not contain both orders")
# I close the rescue session
rescue_session.action_pos_session_closing_control()
self.assertEqual(rescue_session.state, 'closed', "Rescue session was not properly closed")
@@ -157,7 +157,7 @@
<field name="user_id" />
<group expand="0" string="Group By">
<filter string="User" domain="[]" context="{'group_by' : 'user_id'}" />
<filter string="Point of Sale" domain="[]" context="{'group_by': 'user_id'}" />
<filter string="Point of Sale" domain="[]" context="{'group_by': 'config_id'}" />
</group>
</search>
</field>
+1 -1
View File
@@ -270,7 +270,7 @@ class Project(models.Model):
def message_subscribe(self, partner_ids=None, channel_ids=None, subtype_ids=None, force=True):
""" Subscribe to all existing active tasks when subscribing to a project """
res = super(Project, self).message_subscribe(partner_ids=partner_ids, channel_ids=channel_ids, subtype_ids=subtype_ids, force=force)
if not subtype_ids or any(subtype.parent_id.model == 'project.task' for subtype in self.env['mail.message.subtype'].browse(subtype_ids)):
if not subtype_ids or any(subtype.parent_id.res_model == 'project.task' for subtype in self.env['mail.message.subtype'].browse(subtype_ids)):
for partner_id in partner_ids or []:
self.mapped('tasks').filtered(lambda task: not task.stage_id.fold and partner_id not in task.message_partner_ids.ids).message_subscribe(
partner_ids=[partner_id], channel_ids=None, subtype_ids=None, force=False)
+30 -3
View File
@@ -553,13 +553,34 @@ class PurchaseOrderLine(models.Model):
line = super(PurchaseOrderLine, self).create(values)
if line.order_id.state == 'purchase':
line.order_id._create_picking()
msg = _("Extra line with %s ") % (line.product_id.display_name,)
line.order_id.message_post(body=msg)
return line
@api.multi
def write(self, values):
orders = False
if 'product_qty' in values:
changed_lines = self.filtered(lambda x: x.order_id.state == 'purchase')
if changed_lines:
orders = changed_lines.mapped('order_id')
for order in orders:
order_lines = changed_lines.filtered(lambda x: x.order_id == order)
msg = ""
if any([values['product_qty'] < x.product_qty for x in order_lines]):
msg += "<b>" + _('The ordered quantity has been decreased. Do not forget to take it into account on your bills and receipts.') + '</b><br/>'
msg += "<ul>"
for line in order_lines:
msg += "<li> %s:" % (line.product_id.display_name,)
msg += "<br/>" + _("Ordered Quantity") + ": %s -> %s <br/>" % (line.product_qty, float(values['product_qty']),)
if line.product_id.type in ('product', 'consu'):
msg += _("Received Quantity") + ": %s <br/>" % (line.qty_received,)
msg += _("Billed Quantity") + ": %s <br/></li>" % (line.qty_invoiced,)
msg += "</ul>"
order.message_post(body=msg)
result = super(PurchaseOrderLine, self).write(values)
orders = self.filtered(lambda x: x.order_id.state == 'purchase').mapped('order_id')
orders._create_picking()
if orders:
orders._create_picking()
return result
name = fields.Text(string='Description', required=True)
@@ -959,6 +980,12 @@ class ProcurementOrder(models.Model):
'group_id': group
}
def _make_po_select_supplier(self, suppliers):
""" Method intended to be overridden by customized modules to implement any logic in the
selection of supplier.
"""
return suppliers[0]
@api.multi
def make_po(self):
cache = {}
@@ -968,7 +995,7 @@ class ProcurementOrder(models.Model):
if not suppliers:
procurement.message_post(body=_('No vendor associated to product %s. Please set one to fix this procurement.') % (procurement.product_id.name))
continue
supplier = suppliers[0]
supplier = procurement._make_po_select_supplier(suppliers)
partner = supplier.name
gpo = procurement.rule_id.group_propagation_option
+5 -2
View File
@@ -481,8 +481,11 @@ class Report(models.Model):
out, err = process.communicate()
if process.returncode not in [0, 1]:
raise UserError(_('Wkhtmltopdf failed (error code: %s). '
'Message: %s') % (str(process.returncode), err))
if process.returncode == -11:
message = _('Wkhtmltopdf failed (error code: %s). Memory limit too low or maximum file number of subprocess reached. Message : %s')
else:
message = _('Wkhtmltopdf failed (error code: %s). Message: %s')
raise UserError(message % (str(process.returncode), err[-1000:]))
# Save the pdf in attachment if marked
if reporthtml[0] is not False:
+1 -1
View File
@@ -6,7 +6,7 @@ from odoo import api, fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
paperformat_id = fields.Many2one('report.paperformat', 'Paper format')
paperformat_id = fields.Many2one('report.paperformat', 'Paper format', default=lambda self: self.env.ref('report.paperformat_euro', raise_if_not_found=False))
external_report_layout = fields.Selection([
('background', 'Background'),
('boxed', 'Boxed'),
+4
View File
@@ -84,6 +84,10 @@ class AccountInvoice(models.Model):
return report_pages
@api.multi
def get_delivery_partner_id(self):
self.ensure_one()
return self.partner_shipping_id.id or super(AccountInvoice, self).get_delivery_partner_id()
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
+37 -8
View File
@@ -61,7 +61,9 @@ class SaleOrder(models.Model):
for inv in invoice_ids:
refund_ids += refund_ids.search([('type', '=', 'out_refund'), ('origin', '=', inv.number), ('origin', '!=', False), ('journal_id', '=', inv.journal_id.id)])
line_invoice_status = [line.invoice_status for line in order.order_line]
# Ignore the status of the deposit product
deposit_product_id = self.env['sale.advance.payment.inv']._default_product_id()
line_invoice_status = [line.invoice_status for line in order.order_line if line.product_id != deposit_product_id]
if order.state not in ('sale', 'done'):
invoice_status = 'no'
@@ -511,11 +513,11 @@ class SaleOrder(models.Model):
group = tax.tax_group_id
res.setdefault(group, 0.0)
amount = tax.compute_all(line.price_reduce + base_tax, quantity=line.product_uom_qty,
product=line.product_id, partner=line.order_partner_id)['taxes'][0]['amount']
product=line.product_id, partner=self.partner_shipping_id)['taxes'][0]['amount']
res[group] += amount
if tax.include_base_amount:
base_tax += tax.compute_all(line.price_reduce + base_tax, quantity=1, product=line.product_id,
partner=line.order_partner_id)['taxes'][0]['amount']
partner=self.partner_shipping_id)['taxes'][0]['amount']
res = sorted(res.items(), key=lambda l: l[0].sequence)
res = map(lambda l: (l[0].name, l[1]), res)
return res
@@ -562,7 +564,7 @@ class SaleOrderLine(models.Model):
"""
for line in self:
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_id)
taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_shipping_id)
line.update({
'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
'price_total': taxes['total_included'],
@@ -628,7 +630,7 @@ class SaleOrderLine(models.Model):
fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id
# If company_id is set, always filter taxes by the company
taxes = line.product_id.taxes_id.filtered(lambda r: not line.company_id or r.company_id == line.company_id)
line.tax_id = fpos.map_tax(taxes, line.product_id, line.order_id.partner_id) if fpos else taxes
line.tax_id = fpos.map_tax(taxes, line.product_id, line.order_id.partner_shipping_id) if fpos else taxes
@api.multi
def _prepare_order_line_procurement(self, group_id=False):
@@ -692,16 +694,37 @@ class SaleOrderLine(models.Model):
line = super(SaleOrderLine, self).create(values)
if line.state == 'sale':
line._action_procurement_create()
msg = _("Extra line with %s ") % (line.product_id.display_name,)
line.order_id.message_post(body=msg)
return line
@api.multi
def write(self, values):
lines = False
changed_lines = False
if 'product_uom_qty' in values:
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
lines = self.filtered(
lambda r: r.state == 'sale' and float_compare(r.product_uom_qty, values['product_uom_qty'], precision_digits=precision) == -1)
changed_lines = self.filtered(
lambda r: r.state == 'sale' and float_compare(r.product_uom_qty, values['product_uom_qty'], precision_digits=precision) != 0)
if changed_lines:
orders = self.mapped('order_id')
for order in orders:
order_lines = changed_lines.filtered(lambda x: x.order_id == order)
msg = ""
if any([values['product_uom_qty'] < x.product_uom_qty for x in order_lines]):
msg += "<b>" + _('The ordered quantity has been decreased. Do not forget to take it into account on your invoices and delivery orders.') + '</b>'
msg += "<ul>"
for line in order_lines:
msg += "<li> %s:" % (line.product_id.display_name,)
msg += "<br/>" + _("Ordered Quantity") + ": %s -> %s <br/>" % (line.product_uom_qty, float(values['product_uom_qty']),)
if line.product_id.type in ('consu', 'product'):
msg += _("Delivered Quantity") + ": %s <br/>" % (line.qty_delivered,)
msg += _("Invoiced Quantity") + ": %s <br/>" % (line.qty_invoiced,)
msg += "</ul>"
order.message_post(body=msg)
result = super(SaleOrderLine, self).write(values)
if lines:
lines._action_procurement_create()
@@ -825,10 +848,16 @@ class SaleOrderLine(models.Model):
@api.multi
def _get_display_price(self, product):
# TO DO: move me in master/saas-16 on sale.order
if self.order_id.pricelist_id.discount_policy == 'without_discount':
if self.order_id.pricelist_id.discount_policy == 'with_discount':
return product.with_context(pricelist=self.order_id.pricelist_id.id).price
price, rule_id = self.order_id.pricelist_id.get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
pricelist_item = self.env['product.pricelist.item'].browse(rule_id)
if (pricelist_item.base == 'pricelist' and pricelist_item.base_pricelist_id.discount_policy == 'with_discount'):
price, rule_id = pricelist_item.base_pricelist_id.get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
return price
else:
from_currency = self.order_id.company_id.currency_id
return from_currency.compute(product.lst_price, self.order_id.pricelist_id.currency_id)
return product.with_context(pricelist=self.order_id.pricelist_id.id).price
@api.multi
@api.onchange('product_id')
@@ -968,7 +997,7 @@ class SaleOrderLine(models.Model):
new_list_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id, rule_id, self.product_uom_qty, self.product_uom, self.order_id.pricelist_id.id)
new_list_price = self.env['account.tax']._fix_tax_included_price(new_list_price, self.product_id.taxes_id, self.tax_id)
if price != 0 and new_list_price != 0:
if new_list_price != 0:
if self.product_id.company_id and self.order_id.pricelist_id.currency_id != self.product_id.company_id.currency_id:
# new_list_price is in company's currency while price in pricelist currency
new_list_price = self.env['res.currency'].browse(currency_id).with_context(context_partner).compute(new_list_price, self.order_id.pricelist_id.currency_id)
+13 -1
View File
@@ -12,7 +12,19 @@ class SaleOrderLine(models.Model):
lines = {}
if not domain:
# To filter on analyic lines linked to an expense
domain = [('so_line', 'in', self.ids), ('amount', '<=', 0.0)]
expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False)
expense_type_id = expense_type_id and expense_type_id.id
domain = [
('so_line', 'in', self.ids),
'|',
('amount', '<', 0),
'&',
('amount', '=', 0),
'|',
('move_id', '=', False),
('move_id.account_id.user_type_id', '=', expense_type_id)
]
data = self.env['account.analytic.line'].read_group(
domain,
['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False
+14 -1
View File
@@ -142,5 +142,18 @@ class SaleOrderLine(models.Model):
def _compute_analytic(self, domain=None):
if not domain:
# To filter on analyic lines linked to an expense
domain = [('so_line', 'in', self.ids), '|', ('amount', '<=', 0.0), ('project_id', '!=', False)]
expense_type_id = self.env.ref('account.data_account_type_expenses', raise_if_not_found=False)
expense_type_id = expense_type_id and expense_type_id.id
domain = [
('so_line', 'in', self.ids),
'|',
'|',
('amount', '<', 0.0),
('project_id', '!=', False),
'&',
('amount', '=', 0),
'|',
('move_id', '=', False),
('move_id.account_id.user_type_id', '=', expense_type_id)
]
return super(SaleOrderLine, self)._compute_analytic(domain=domain)
@@ -4,10 +4,12 @@
<record id="team_sales_department" model="crm.team">
<field name="name">Sales</field>
<field name="member_ids" eval="[(4, ref('base.user_root'))]"/>
<field name="company_id" eval="False"/>
</record>
<record id="salesteam_website_sales" model="crm.team">
<field name="name">Website</field>
<field name="company_id" eval="False"/>
<field name="active" eval="False"/>
<field name="team_type" eval="'website'"/>
</record>
+5 -3
View File
@@ -24,9 +24,11 @@ class CrmTeam(models.Model):
def _get_default_team_id(self, user_id=None):
if not user_id:
user_id = self.env.uid
team_id = self.env['crm.team'].sudo().search(
['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)],
limit=1)
company_id = self.sudo(user_id).company_id.id
team_id = self.env['crm.team'].sudo().search([
'|', ('user_id', '=', user_id), ('member_ids', '=', user_id),
'|', ('company_id', '=', False), ('company_id', 'child_of', [company_id])
], limit=1)
if not team_id and 'default_team_id' in self.env.context:
team_id = self.env['crm.team'].browse(self.env.context.get('default_team_id'))
if not team_id:
@@ -84,7 +84,7 @@
</a>
</td>
<td t-if="show_demo or (values and values['closing']['overdue'] != 0)" class="o_warning" title="To Opportunities">
<a href="#" class="o_dashboard_action" name="crm.action_your_pipeline" data-context="{'search_default_overdue_opp':'1'}">
<a href="#" class="o_dashboard_action" name="crm.crm_lead_action_activities" data-context="{'search_default_overdue_opp':'1'}">
<t t-if="!show_demo">
<t t-esc="values['closing']['overdue']"/> exp. closing
</t>
+17 -15
View File
@@ -275,23 +275,27 @@ class ProcurementOrder(models.Model):
@api.model
def _procure_orderpoint_confirm(self, use_new_cursor=False, company_id=False):
""" Create procurements based on orderpoints.
:param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement.
:param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing
1000 orderpoints.
This is appropriate for batch jobs only.
"""
if use_new_cursor:
cr = registry(self._cr.dbname).cursor()
self = self.with_env(self.env(cr=cr))
OrderPoint = self.env['stock.warehouse.orderpoint']
Procurement = self.env['procurement.order']
ProcurementAutorundefer = Procurement.with_context(procurement_autorun_defer=True)
procurement_list = []
orderpoints_noprefetch = OrderPoint.with_context(prefetch_fields=False).search(
company_id and [('company_id', '=', company_id)] or [],
order=self._procurement_from_orderpoint_get_order())
domain = [('company_id', '=', company_id)] if company_id else []
domain += [('product_id.active', '=', True)]
orderpoints_noprefetch = OrderPoint.with_context(prefetch_fields=False).search(domain,
order=self._procurement_from_orderpoint_get_order()).ids
while orderpoints_noprefetch:
orderpoints = OrderPoint.browse(orderpoints_noprefetch[:1000].ids)
if use_new_cursor:
cr = registry(self._cr.dbname).cursor()
self = self.with_env(self.env(cr=cr))
OrderPoint = self.env['stock.warehouse.orderpoint']
Procurement = self.env['procurement.order']
ProcurementAutorundefer = Procurement.with_context(procurement_autorun_defer=True)
procurement_list = []
orderpoints = OrderPoint.browse(orderpoints_noprefetch[:1000])
orderpoints_noprefetch = orderpoints_noprefetch[1000:]
# Calculate groups that can be executed together
@@ -341,7 +345,7 @@ class ProcurementOrder(models.Model):
except OperationalError:
if use_new_cursor:
orderpoints_noprefetch += orderpoint.id
orderpoints_noprefetch += [orderpoint.id]
cr.rollback()
continue
else:
@@ -365,8 +369,6 @@ class ProcurementOrder(models.Model):
if use_new_cursor:
cr.commit()
cr.close()
if use_new_cursor:
cr.commit()
cr.close()
return {}
+12 -10
View File
@@ -349,7 +349,7 @@ class StockMove(models.Model):
raise UserError(_('Cannot unreserve a done move'))
self.quants_unreserve()
if not self.env.context.get('no_state_change'):
waiting = self.filtered(lambda move: move.get_ancestors())
waiting = self.filtered(lambda move: move.procure_method == 'make_to_order' or move.get_ancestors())
waiting.write({'state': 'waiting'})
(self - waiting).write({'state': 'confirmed'})
@@ -408,15 +408,8 @@ class StockMove(models.Model):
type (moves should already have them identical). Otherwise, create a new
picking to assign them to. """
Picking = self.env['stock.picking']
# If this method is called in batch by a write on a one2many and
# at some point had to create a picking, some next iterations could
# try to find back the created picking. As we look for it by searching
# on some computed fields, we have to force a recompute, else the
# record won't be found.
self.recompute()
for move in self:
recompute = False
picking = Picking.search([
('group_id', '=', move.group_id.id),
('location_id', '=', move.location_id.id),
@@ -425,8 +418,17 @@ class StockMove(models.Model):
('printed', '=', False),
('state', 'in', ['draft', 'confirmed', 'waiting', 'partially_available', 'assigned'])], limit=1)
if not picking:
recompute = True
picking = Picking.create(move._get_new_picking_values())
move.write({'picking_id': picking.id})
# If this method is called in batch by a write on a one2many and
# at some point had to create a picking, some next iterations could
# try to find back the created picking. As we look for it by searching
# on some computed fields, we have to force a recompute, else the
# record won't be found.
if recompute:
move.recompute()
return True
_picking_assign = assign_picking
@@ -687,7 +689,7 @@ class StockMove(models.Model):
if len(reserved_quant_ids) == 0 and move.partially_available:
vals['partially_available'] = False
if move.state == 'assigned':
if move.find_move_ancestors():
if move.procure_method == 'make_to_order' or move.find_move_ancestors():
vals['state'] = 'waiting'
else:
vals['state'] = 'confirmed'
@@ -19,6 +19,9 @@
<div t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": True}'/>
</div>
<div t-if="not (o.move_lines and o.move_lines[0].partner_id) and o.partner_id" name="partner_header">
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true}'/>
</div>
</div>
</div>
<h2>
+66 -1
View File
@@ -1726,4 +1726,69 @@ class TestStockFlow(TestStockCommon):
# force assign on the delivery order, it should be assigned
picking_out.force_assign()
self.assertEquals(picking_out.state, "assigned")
self.assertEquals(picking_out.state, "assigned")
def test_74_move_state_waiting_mto(self):
""" This test will check that when a move is unreserved, it state change to 'waiting' if
it has ancestors or is has a 'procure_method' equal to 'make_to_order' else the state
changes to 'confirmed'.
"""
picking_out = self.PickingObj.create({
'partner_id': self.partner_agrolite_id,
'picking_type_id': self.picking_type_out,
'location_id': self.stock_location,
'location_dest_id': self.customer_location})
move_mto_alone = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_out.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'procure_method':'make_to_order'})
move_with_ancestors = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_out.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location})
the_ancestor = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_out.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'move_dest_id': move_with_ancestors.id})
other_move = self.MoveObj.create({
'name': self.productA.name,
'product_id': self.productA.id,
'product_uom_qty': 2,
'product_uom': self.productA.uom_id.id,
'picking_id': picking_out.id,
'location_id': self.stock_location,
'location_dest_id': self.customer_location})
move_mto_alone.action_confirm()
move_with_ancestors.action_confirm()
other_move.action_confirm()
move_mto_alone.do_unreserve()
move_with_ancestors.do_unreserve()
other_move.do_unreserve()
self.assertEquals(move_mto_alone.state, "waiting")
self.assertEquals(move_with_ancestors.state, "waiting")
self.assertEquals(other_move.state, "confirmed")
move_mto_alone.recalculate_move_state()
move_with_ancestors.recalculate_move_state()
other_move.recalculate_move_state()
self.assertEquals(move_mto_alone.state, "waiting")
self.assertEquals(move_with_ancestors.state, "waiting")
self.assertEquals(other_move.state, "confirmed")
@@ -98,6 +98,7 @@
<field name="model">stock.warehouse</field>
<field name="arch" type="xml">
<search string="Warehouse">
<field name="name"/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
</search>
</field>
+1 -1
View File
@@ -188,7 +188,7 @@ class StockMove(models.Model):
tmpl_dict = defaultdict(lambda: 0.0)
# adapt standard price on incomming moves if the product cost_method is 'average'
std_price_update = {}
for move in self.filtered(lambda move: move.location_id.usage == 'supplier' and move.product_id.cost_method == 'average'):
for move in self.filtered(lambda move: move.location_id.usage in ('supplier', 'production') and move.product_id.cost_method == 'average'):
product_tot_qty_available = move.product_id.qty_available + tmpl_dict[move.product_id.id]
# if the incoming move is for a purchase order with foreign currency, need to call this to get the same value that the quant will use.
@@ -129,6 +129,7 @@ class LandedCost(models.Model):
if quant.location_id.usage != 'internal':
qty_out += quant.qty
line._create_accounting_entries(move, qty_out)
move.assert_balanced()
cost.write({'state': 'done', 'account_move_id': move.id})
move.post()
return True
@@ -326,7 +327,7 @@ class AdjustmentLines(models.Model):
Generate the account.move.line values to track the landed cost.
Afterwards, for the goods that are already out of stock, we should create the out moves
"""
AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False)
AccountMoveLine = self.env['account.move.line'].with_context(check_move_validity=False, recompute=False)
base_line = {
'name': self.name,
@@ -389,5 +390,4 @@ class AdjustmentLines(models.Model):
AccountMoveLine.create(debit_line)
AccountMoveLine.create(credit_line)
move.assert_balanced()
return True
+4
View File
@@ -665,6 +665,8 @@ class Database(http.Controller):
@http.route('/web/database/create', type='http', auth="none", methods=['POST'], csrf=False)
def create(self, master_pwd, name, lang, password, **post):
try:
if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', name):
raise Exception(_('Invalid database name. Only alphanumerical characters and underscore are allowed.'))
# country code could be = "False" which is actually True in python
country_code = post.get('country_code') or False
dispatch_rpc('db', 'create_database', [master_pwd, name, bool(post.get('demo')), lang, password, post['login'], country_code])
@@ -677,6 +679,8 @@ class Database(http.Controller):
@http.route('/web/database/duplicate', type='http', auth="none", methods=['POST'], csrf=False)
def duplicate(self, master_pwd, name, new_name):
try:
if not re.match('^[a-zA-Z][a-zA-Z0-9_]+$', new_name):
raise Exception(_('Invalid database name. Only alphanumerical characters and underscore are allowed.'))
dispatch_rpc('db', 'duplicate_database', [master_pwd, name, new_name])
return http.local_redirect('/web/database/manager')
except Exception as e:
@@ -25,6 +25,13 @@ var KanbanView = BasicView.extend({
this._super.apply(this, arguments);
var arch = viewInfo.arch;
this.loadParams.limit = this.loadParams.limit || 40;
this.loadParams.openGroupByDefault = true;
this.loadParams.type = 'list';
this.loadParams.groupBy = arch.attrs.default_group_by ? [arch.attrs.default_group_by] : (params.groupBy || []);
var activeActions = this.controllerParams.activeActions;
activeActions = _.extend(activeActions, {
group_edit: arch.attrs.group_edit ? JSON.parse(arch.attrs.group_edit) : true,
@@ -35,7 +42,7 @@ var KanbanView = BasicView.extend({
editable: activeActions.group_edit,
deletable: activeActions.group_delete,
group_creatable: true,
quick_create: params.isQuickCreateEnabled || this._isQuickCreateEnabled(arch),
quick_create: params.isQuickCreateEnabled || this._isQuickCreateEnabled(viewInfo),
};
this.rendererParams.record_options = {
editable: activeActions.edit,
@@ -47,19 +54,17 @@ var KanbanView = BasicView.extend({
this.controllerParams.readOnlyMode = false;
this.controllerParams.hasButtons = true;
this.loadParams.limit = this.loadParams.limit || 40;
this.loadParams.openGroupByDefault = true;
this.loadParams.type = 'list';
this.loadParams.groupBy = arch.attrs.default_group_by ? [arch.attrs.default_group_by] : (params.groupBy || []);
},
_isQuickCreateEnabled: function (arch) {
_isQuickCreateEnabled: function (viewInfo) {
var groupBy = this.loadParams.groupBy[0];
if(groupBy !== undefined && !_.contains(['char', 'boolean', 'many2one'], viewInfo.fields[groupBy].type)) {
return false;
}
if (!this.controllerParams.activeActions.create) {
return false;
}
if (arch.attrs.quick_create !== undefined) {
return JSON.parse(arch.attrs.quick_create);
if (viewInfo.arch.attrs.quick_create !== undefined) {
return JSON.parse(viewInfo.arch.attrs.quick_create);
}
return true;
}
@@ -207,9 +207,15 @@ var DataExport = Dialog.extend({
this.records = {};
this.dataset = dataset;
this.exports = new data.DataSetSearch(this, 'ir.exports', this.dataset.get_context());
this.row_index = 0;
this.row_index_level = 0;
// The default for the ".modal_content" element is "max-height: 100%;"
// but we want it to always expand to "height: 100%;" for this modal.
// This can be achieved thanks to LESS modification without touching
// the ".modal-content" rules... but not with Internet explorer (11).
this.$modal.find(".modal-content").css("height", "100%");
},
start: function() {
var self = this;
@@ -265,7 +271,7 @@ var DataExport = Dialog.extend({
function do_setup_export_formats(formats) {
var $fmts = self.$('.o_export_format');
_.each(formats, function(format, i) {
var $radio = $('<input/>', {type: 'radio', value: format.tag, name: 'o_export_format_name'});
var $label = $('<label/>', {html: format.label});
@@ -374,7 +380,7 @@ var DataExport = Dialog.extend({
},
on_show_data: function(records, expansion) {
var self = this;
if(expansion) {
this.$('.o_export_tree_item[data-id="' + expansion + '"]')
.addClass('open')
+8 -6
View File
@@ -1,8 +1,8 @@
.o_web_client .o_export {
.o-flex(0, 1, 1000px);
.o-flex(1, 1, auto);
.o-flex-display();
.o-flex-flow(column, nowrap);
min-height: 0;
> p, > .row {
.o-flex(0, 0, auto);
@@ -28,8 +28,9 @@
}
.o_export_panel {
.o-flex(1, 0, 0);
.o-flex(1, 1, auto);
position: relative;
min-height: 0;
> div {
height: 100%;
@@ -59,9 +60,10 @@
.o_left_field_panel, .o_fields_list {
border: 1px solid @odoo-brand-lightsecondary;
overflow: auto;
.o-flex(1, 0, 0);
.o-flex(1, 1, auto);
min-height: 0;
}
.o_export_tree_item {
cursor: pointer;
position: relative;
@@ -72,7 +74,7 @@
background-color: @odoo-brand-primary;
color: white;
}
.o_expand_parent {
.o-position-absolute(@top: 4px, @left: 5px);
}
+3 -3
View File
@@ -60,7 +60,7 @@
<div class="row">
<div class="col-md-12">
<label for="name" class="control-label">Database Name</label>
<input id="name" type="text" name="name" class="form-control" required="required" autocomplete="off"/>
<input id="name" type="text" name="name" class="form-control" required="required" autocomplete="off" pattern="^[a-zA-Z][a-zA-Z0-9_]+$" title="Only alphanumerical characters and underscore are allowed"/>
</div>
</div>
</div>
@@ -210,7 +210,7 @@
</div>
<div class="form-group">
<label for="name" class="control-label">Database Name</label>
<input id="name" type="text" name="name" class="form-control" required="required"/>
<input id="name" type="text" name="name" class="form-control" required="required" pattern="^[a-zA-Z][a-zA-Z0-9_]+$" title="Only alphanumerical characters and underscore are allowed"/>
</div>
<div class="form-group">
<label for="copy">This database might have been moved or copied.</label>
@@ -283,7 +283,7 @@
</div>
<div class="form-group">
<label for="new_name" class="control-label">New Name</label>
<input id="new_name" type="text" name="new_name" class="form-control" required="required"/>
<input id="new_name" type="text" name="new_name" class="form-control" required="required" pattern="^[a-zA-Z][a-zA-Z0-9_]+$" title="Only alphanumerical characters and underscore are allowed"/>
</div>
</div>
<div class="modal-footer">
@@ -292,7 +292,15 @@ eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) {
$imagePopover.find('.o_image_alt').text( (alt || "").replace(/&quot;/g, '"') ).parent().toggle(oStyle.image.tagName === "IMG");
$imagePopover.show();
range.createFromNode(dom.firstChild(oStyle.image)).select();
// for video tag (non-void) we select the range over the tag,
// for other media types we get the first descendant leaf element
var target_node = oStyle.image;
if (!oStyle.image.className.match(/(^|\s)media_iframe_video(\s|$)/i)) {
target_node = dom.firstChild(target_node);
}
range.createFromNode(target_node).select();
// save range on the editor so it is not lost if restored
eventHandler.modules.editor.saveRange(dom.makeLayoutInfo(target_node).editable());
} else {
$(".note-control-selection").hide();
}
+6 -6
View File
@@ -636,9 +636,12 @@ var fontIconsDialog = Widget.extend({
},
renderElement: function () { // extract list of font (like awesome) from the cheatsheet.
this.iconsParser = fontIcons;
this.icons = _.flatten(_.map(fontIcons, function (data) {
this.icons = _.flatten(_.map(fontIcons, function (data) { // TODO maybe useless now
return data.icons;
}));
this.alias = _.flatten(_.map(fontIcons, function (data) {
return data.alias;
}));
this._super.apply(this, arguments);
},
search: function (needle) {
@@ -740,11 +743,8 @@ var fontIconsDialog = Widget.extend({
case '': continue;
default:
$(".font-icons-icon").removeClass("o_selected").filter("[data-alias*=',"+cls+",']").addClass("o_selected");
for (var k=0; k<this.icons.length; k++) {
if (this.icons.indexOf(cls) !== -1) {
this.$('#fa-icon').val(cls);
break;
}
if (this.alias.indexOf(cls) !== -1) {
this.$('#fa-icon').val(cls);
}
}
}
@@ -300,7 +300,8 @@ return core.Class.extend(mixins.EventDispatcherMixin, ServicesMixin, {
this.update();
}).bind(this));
window.location.href = session.debug ? $.param.querystring(tour.url, {debug: session.debug}) : tour.url;
var url = session.debug ? $.param.querystring(tour.url, {debug: session.debug}) : tour.url;
window.location.href = window.location.origin + url;
} else {
this.update();
}
+9 -3
View File
@@ -72,13 +72,19 @@ class WebsiteConfigSettings(models.TransientModel):
config.language_count = len(self.language_ids)
def set_has_google_analytics(self):
return self.env['ir.values'].set_default(
if not self.user_has_groups('website.group_website_designer'):
raise AccessDenied()
return self.env['ir.values'].sudo().set_default(
'website.config.settings', 'has_google_analytics', self.has_google_analytics)
def set_has_google_analytics_dashboard(self):
return self.env['ir.values'].set_default(
if not self.user_has_groups('website.group_website_designer'):
raise AccessDenied()
return self.env['ir.values'].sudo().set_default(
'website.config.settings', 'has_google_analytics_dashboard', self.has_google_analytics_dashboard)
def set_has_google_maps(self):
return self.env['ir.values'].set_default(
if not self.user_has_groups('website.group_website_designer'):
raise AccessDenied()
return self.env['ir.values'].sudo().set_default(
'website.config.settings', 'has_google_maps', self.has_google_maps)
@@ -339,6 +339,7 @@ var MenuEntryDialog = widget.LinkDialog.extend({
return {
'TopBar': TopBarContent,
'EditMenuDialog': EditMenuDialog,
};
});
+1 -1
View File
@@ -99,7 +99,7 @@
<t t-set="title" t-value="main_object.website_meta_title"/>
</t>
<t t-else="">
<t t-set="title"><t t-if="additional_title"><t t-raw="additional_title"/> | </t><t t-esc="(website or res_company).name"/></t>
<t t-set="title"><t t-if="additional_title"><t t-raw="additional_title"/> | </t><t t-raw="(website or res_company).name"/></t>
</t>
</t>
<t t-set="x_icon" t-value="'/web/image/website/%s/favicon/' % website.id"/>
@@ -43,7 +43,7 @@
</div>
<div class="o_setting_right_pane">
<label for="use_questions"/>
<div class="row mt16" attrs="{'invisible': [('use_ticketing', '=', False)]}">
<div class="row mt16" attrs="{'invisible': [('use_questions', '=', False)]}">
<div class="col-md-9">
<field name="question_ids"/>
</div>
+13 -1
View File
@@ -11,6 +11,12 @@ class EventType(models.Model):
website_track = fields.Boolean('Tracks on Website')
website_track_proposal = fields.Boolean('Tracks Proposals on Website')
@api.onchange('website_menu')
def _onchange_website_menu(self):
if not self.website_menu:
self.website_track = False
self.website_track_proposal = False
class Event(models.Model):
_inherit = "event.event"
@@ -64,10 +70,16 @@ class Event(models.Model):
@api.onchange('event_type_id')
def _onchange_type(self):
super(Event, self)._onchange_type()
if self.event_type_id:
if self.event_type_id and self.website_menu:
self.website_track = self.event_type_id.website_track
self.website_track_proposal = self.event_type_id.website_track_proposal
@api.onchange('website_menu')
def _onchange_website_menu(self):
if not self.website_menu:
self.website_track = False
self.website_track_proposal = False
def _get_menu_entries(self):
self.ensure_one()
res = super(Event, self)._get_menu_entries()
@@ -83,7 +83,8 @@
<span t-if="not track.website_published" class="label label-warning">unpublished</span>
</a>
<div class="text-muted">
<small t-esc="track.partner_id.sudo().name"/>
<small t-if="track.partner_id" t-esc="track.partner_id.sudo().name"/>
<small t-if="not track.partner_id" t-esc="track.partner_name"/>
</div>
</t>
</td>
@@ -98,7 +99,8 @@
<span t-esc="track.name"/>
</a>
<div class="text-muted">
<small t-esc="track.partner_id.sudo()"/>
<small t-if="track.partner_id" t-esc="track.partner_id.sudo().name"/>
<small t-if="not track.partner_id" t-esc="track.partner_name"/>
</div>
</td>
</t>
@@ -213,7 +215,10 @@
<div class="row">
<div class="col-md-12 text-center">
<h2 t-field="track.name"/>
<small>Proposed by <span t-field="track.partner_name"/></small>
<small>Proposed by
<span t-if="track.partner_id" t-field="track.partner_id.sudo().name"/>
<span t-if="not track.partner_id" t-field="track.partner_name"/>
</small>
</div>
<div class="col-md-12">
<p t-field="track.description"/>
@@ -121,6 +121,7 @@
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
</button>
</div>
<field name="kanban_state" widget="kanban_state_selection"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
@@ -7,10 +7,10 @@
<field name="inherit_id" ref="website_event.event_type_view_form_inherit_website"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='event_type_visibility_website']/div[@class='o_setting_right_pane']" position='inside'>
<div class="row mt16">
<div class="row mt16" attrs="{'invisible': [('website_menu', '=', False)]}">
<label class="col-md-4" for="website_track"/> <field name="website_track"/>
</div>
<div class="row mt16">
<div class="row mt16" attrs="{'invisible': [('website_menu', '=', False)]}">
<label class="col-md-4" for="website_track_proposal"/> <field name="website_track_proposal"/>
</div>
</xpath>
@@ -149,7 +149,7 @@ class PortalWizardUser(models.TransientModel):
wizard_user.user_id.write({'active': True, 'groups_id': [(4, group_portal.id)]})
# prepare for the signup process
wizard_user.user_id.partner_id.signup_prepare()
wizard_user._send_email()
wizard_user.with_context(active_test=True)._send_email()
wizard_user.refresh()
else:
# remove the user (if it exists) from the portal group
@@ -88,6 +88,14 @@ class SaleOrder(models.Model):
super(SaleOrder, self).onchange_partner_id()
self.note = self.template_id.note or self.note
@api.onchange('partner_id')
def onchange_update_description_lang(self):
if not self.template_id:
return
else:
template = self.template_id.with_context(lang=self.partner_id.lang)
self.website_description = template.website_description
@api.onchange('template_id')
def onchange_template_id(self):
if not self.template_id:
+12 -4
View File
@@ -67,12 +67,11 @@ class SaleOrder(models.Model):
'pricelist': order.pricelist_id.id,
})
product = self.env['product.product'].with_context(product_context).browse(product_id)
pu = product.price
if order.pricelist_id and order.partner_id:
order_line = order._cart_find_product_line(product.id)
if order_line:
pu = self.env['account.tax']._fix_tax_included_price(order_line._get_display_price(product), product.taxes_id, order_line.tax_id)
pu = self.env['account.tax']._fix_tax_included_price(pu, product.taxes_id, order_line.tax_id)
return {
'product_id': product_id,
@@ -149,10 +148,19 @@ class SaleOrder(models.Model):
else:
# update line
values = self._website_product_id_change(self.id, product_id, qty=quantity)
if self.pricelist_id.discount_policy == 'with_discount' and not self.env.context.get('fixed_price'):
order = self.sudo().browse(self.id)
product_context = dict(self.env.context)
product_context.setdefault('lang', order.partner_id.lang)
product_context.update({
'partner': order.partner_id.id,
'quantity': quantity,
'date': order.date_order,
'pricelist': order.pricelist_id.id,
})
product = self.env['product.product'].with_context(product_context).browse(product_id)
values['price_unit'] = self.env['account.tax']._fix_tax_included_price(
order_line._get_display_price(order_line.product_id),
order_line._get_display_price(product),
order_line.product_id.taxes_id,
order_line.tax_id
)
@@ -449,6 +449,10 @@ label.css_attribute_color.css_not_available {
text-align: center;
}
.oe_website_sale input.quantity {
padding: 0;
}
/* ---- Publish managment and options ---- */
.oe_overlay_options .dropdown ul[name="size"] table {
margin-left: 20px;
@@ -388,6 +388,9 @@ label.css_attribute_color.css_not_available
min-width: 48px
text-align: center
.oe_website_sale input.quantity
padding: 0
/* ---- Publish managment and options ---- */
.oe_overlay_options
@@ -74,6 +74,7 @@ odoo.define('website_sale.website_sale', function (require) {
var ajax = require('web.ajax');
var utils = require('web.utils');
var core = require('web.core');
var config = require('web.config');
var _t = core._t;
if(!$('.oe_website_sale').length) {
@@ -295,8 +296,10 @@ odoo.define('website_sale.website_sale', function (require) {
var $ul = $(ev.target).closest('.js_add_cart_variants');
var $parent = $ul.closest('.js_product');
var $product_id = $parent.find('input.product_id').first();
var $price = $parent.find(".oe_price:first .oe_currency_value");
var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
var $price = $parent.find(".oe_price:first .oe_currency_value")
.add($('#product_confirmation').find(".oe_price"));
var $default_price = $parent.find(".oe_default_price:first .oe_currency_value")
.add($('#product_confirmation').find(".oe_default_price:first .oe_currency_value"));
var $optional_price = $parent.find(".oe_optional:first .oe_currency_value");
var variant_ids = $ul.data("attribute_value_ids");
var values = [];
@@ -454,5 +457,8 @@ odoo.define('website_sale.website_sale', function (require) {
$("select[name='country_id']").change();
});
$('.ecom-zoomable img[data-zoom]').zoomOdoo({ attach: '#o-carousel-product'});
// Deactivate image zoom for mobile devices, since it might prevent users to scroll
if (config.device.size_class > config.device.SIZES.XS) {
$('.ecom-zoomable img[data-zoom]').zoomOdoo({ attach: '#o-carousel-product'});
}
});
@@ -4,6 +4,8 @@ odoo.define('website_sale.utils', function (require) {
var animate_clone = function(cart, $elem, offset_top, offset_left) {
cart.find('.o_animate_blink').addClass('o_red_highlight o_shadow_animation').delay(500).queue(function(){
$(this).removeClass("o_shadow_animation").dequeue();
}).delay(2000).queue(function(){
$(this).removeClass("o_red_highlight").dequeue();
});
var imgtodrag = $elem.find('img').eq(0);
if (imgtodrag.length) {
+3 -6
View File
@@ -582,7 +582,7 @@
<a t-attf-href="#" class="mb8 input-group-addon js_add_cart_json">
<i class="fa fa-minus"></i>
</a>
<input type="text" class="form-control" data-min="1" name="add_qty" value="1"/>
<input type="text" class="form-control quantity" data-min="1" name="add_qty" value="1"/>
<a t-attf-href="#" class="mb8 input-group-addon float_left js_add_cart_json">
<i class="fa fa-plus"></i>
</a>
@@ -613,10 +613,7 @@
<template id="product_variants" inherit_id="website_sale.product" active="False" customize_show="True" name="List View of Variants">
<xpath expr="//t[@t-placeholder='select']" position="replace">
<input type="hidden" t-if="len(product.product_variant_ids) == 1" name="product_id" t-att-value="product.product_variant_id.id"/>
<t t-call="website_sale.variants">
<t t-set="ul_class" t-value="'nav-stacked'"/>
</t>
<input type="hidden" t-if="len(product.product_variant_ids) == 1" class="product_id" name="product_id" t-att-value="product.product_variant_id.id"/>
<t t-if="len(product.product_variant_ids) &gt; 1">
<label label-default="label-default" class="radio" t-foreach="product.product_variant_ids" t-as="variant_id">
<input type="radio" name="product_id" class="js_product_change" t-att-checked="'checked' if variant_id_index == 0 else None" t-att-value="variant_id.id" t-att-data-lst_price="variant_id.lst_price" t-att-data-price="variant_id.price"/>
@@ -890,7 +887,7 @@
<a t-attf-href="#" class="mb8 input-group-addon js_add_cart_json hidden-xs">
<i class="fa fa-minus"></i>
</a>
<input type="text" class="js_quantity form-control" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="int(line.product_uom_qty)" />
<input type="text" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="int(line.product_uom_qty)" />
<a t-attf-href="#" class="mb8 input-group-addon float_left js_add_cart_json hidden-xs">
<i class="fa fa-plus"></i>
</a>
@@ -8,13 +8,13 @@
</xpath>
</template>
<template id="add_to_compare" inherit_id="website_sale.products_item" active="True" customize_show="True" name="Comparison List">
<template id="add_to_compare" inherit_id="website_sale.products_item" active="True" customize_show="True" name="Comparison List" priority="22">
<xpath expr="//div[@class='product_price']" position="inside">
<a class="hidden-xs btn btn-default btn-xs o_add_compare" title="Compare" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_comparelist"><span class="fa fa-exchange"></span></a>
</xpath>
</template>
<template id="product_add_to_compare" name='Add to comparison in product page' inherit_id="website_sale.product">
<template id="product_add_to_compare" name='Add to comparison in product page' inherit_id="website_sale.product" priority="8">
<xpath expr="//a[@id='add_to_cart']" position="after">
<t t-if="product.env.ref('website_sale_comparison.add_to_compare').active">
<a class="hidden-xs btn btn-default btn-lg mt8 o_add_compare_dyn" title="Compare" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_comparelist"><span class="fa fa-exchange"></span></a>
@@ -58,14 +58,14 @@
<a t-attf-href="#" class="mb8 input-group-addon js_add_cart_json hidden-xs">
<i class="fa fa-minus"></i>
</a>
<input type="text" class="js_quantity form-control" data-min="1" name="add_qty" value="1"/>
<input type="text" class="js_quantity form-control quantity" data-min="1" name="add_qty" value="1"/>
<a t-attf-href="#" class="mb8 input-group-addon float_left js_add_cart_json hidden-xs">
<i class="fa fa-plus"></i>
</a>
</div>
</td>
<td class="text-center td-price" name="price">
<span t-attf-class="text-danger oe_default_price" t-att-style="'text-decoration: line-through; white-space: nowrap;' + '' if (compute_currency(product.lst_price) - product.with_context(quantity=1).website_price ) &gt; 0.01 else 'display: none;'"
<span t-attf-class="text-danger oe_default_price" style="text-decoration: line-through; white-space: nowrap;"
t-field="product.lst_price"
t-options='{
"widget": "monetary",
@@ -33,3 +33,9 @@ class ProductWishlist(models.Model):
'product_id': product_id,
})
return wish
class ResPartner(models.Model):
_inherit = 'res.partner'
wishlist_ids = fields.One2many('product.wishlist', 'partner_id', string='Wishlist', domain=[('active', '=', True)])
@@ -31,27 +31,40 @@ var ProductWishlist = Widget.extend({
});
if ($('.wishlist-section').length) {
$('.wishlist-section a.o_wish_rm').on('click', function (e){ self.wishlist_rm(e); });
$('.wishlist-section a.o_wish_add').on('click', function (e){ self.wishlist_add(e); });
$('.wishlist-section a.o_wish_mv').on('click', function (e){ self.wishlist_mv(e); });
$('.wishlist-section a.o_wish_rm').on('click', function (e){ self.wishlist_rm(e, false); });
$('.wishlist-section a.o_wish_add').on('click', function (e){ self.wishlist_add_or_mv(e); });
}
$('.oe_website_sale').on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function(ev) {
var $ul = $(ev.target).closest('.js_add_cart_variants');
var $parent = $ul.closest('.js_product');
var $product_id = $parent.find('.product_id').first();
var $el = $parent.find("[data-action='o_wishlist']");
if (!_.contains(self.wishlist_product_ids, parseInt($product_id.val(), 10))) {
$el.prop("disabled", false).removeClass('disabled').removeAttr('disabled');
}
else {
$el.prop("disabled", true).addClass('disabled').attr('disabled', 'disabled');
}
});
},
add_new_products:function($el, e){
var self = this;
var product_id = $el.data('product-product-id');
if (e.currentTarget.classList.contains('o_add_wishlist_dyn')) {
product_id = parseInt($el.parent().find('.product_id').val());
}
if (odoo.session_info.is_website_user){
this.warning_not_logged();
} else {
var product_id = $el.data('product-product-id');
if (e.currentTarget.classList.contains('o_add_wishlist_dyn')) {
product_id = parseInt($el.parent().find('.product_id').val());
}
if (!_.contains(self.wishlist_product_ids, product_id)) {
return ajax.jsonRpc('/shop/wishlist/add', 'call', {
'product_id': product_id
}).then(function () {
self.wishlist_product_ids.push(product_id);
self.update_wishlist_view();
website_sale_utils.animate_clone($('#my_wish'), $el.closest('form'), 10, 10);
website_sale_utils.animate_clone($('#my_wish'), $el.closest('form'), 25, 40);
$el.prop("disabled", true).addClass('disabled');
});
}
}
@@ -77,10 +90,11 @@ var ProductWishlist = Widget.extend({
$('#my_wish').hide();
}
},
wishlist_rm: function(e){
wishlist_rm: function(e, deferred_redirect){
var tr = $(e.currentTarget).parents('tr');
var wish = tr.data('wish-id');
var product = tr.data('product-id');
var self = this;
rpc.query({
model: 'product.wishlist',
@@ -90,19 +104,26 @@ var ProductWishlist = Widget.extend({
.then(function(){
$(tr).hide();
});
this.wishlist_product_ids = _.without(this.wishlist_product_ids, product);
if (this.wishlist_product_ids.length === 0) {
this.redirect_no_wish();
deferred_redirect = deferred_redirect ? deferred_redirect : $.Deferred();
deferred_redirect.then(function() {
self.redirect_no_wish();
});
}
this.update_wishlist_view();
},
wishlist_add_or_mv: function(e){
return $('#b2b_wish').is(':checked') ? this.wishlist_add(e) : this.wishlist_mv(e);
},
wishlist_add: function(e){
var tr = $(e.currentTarget).parents('tr');
var product = tr.data('product-id');
// can be hidden if empty
$('#my_cart').removeClass('hidden');
website_sale_utils.animate_clone($('#my_cart'), tr, 0, 0);
website_sale_utils.animate_clone($('#my_cart'), tr, 25, 40);
this.add_to_cart(product, tr.find('qty').val() || 1);
},
wishlist_mv: function(e){
@@ -110,15 +131,20 @@ var ProductWishlist = Widget.extend({
var product = tr.data('product-id');
$('#my_cart').removeClass('hidden');
website_sale_utils.animate_clone($('#my_cart'), tr, 0, 0);
this.add_to_cart(product, tr.find('qty').val() || 1);
this.wishlist_rm(e);
website_sale_utils.animate_clone($('#my_cart'), tr, 25, 40);
var adding_deffered = this.add_to_cart(product, tr.find('qty').val() || 1);
this.wishlist_rm(e, adding_deffered);
},
add_to_cart: function(product_id, qty_id) {
ajax.jsonRpc("/shop/cart/update_json", 'call', {
var add_to_cart = ajax.jsonRpc("/shop/cart/update_json", 'call', {
'product_id': parseInt(product_id, 10),
'add_qty': parseInt(qty_id, 10)
});
add_to_cart.then(function(resp) {
$('.my_cart_quantity').text(resp.cart_quantity || '* 1');
});
return add_to_cart;
},
redirect_no_wish: function() {
window.location = '/shop/cart';
@@ -8,16 +8,18 @@
</xpath>
</template>
<template id="add_to_wishlist" inherit_id="website_sale.products_item" active="True" customize_show="True" name="Wishlist" priority="10">
<template id="add_to_wishlist" inherit_id="website_sale.products_item" active="True" customize_show="True" name="Wishlist" priority="20">
<xpath expr="//div[@class='product_price']" position="inside">
<a class="btn btn-default btn-xs o_add_wishlist" title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
<t t-set="in_wish" t-value="product.product_variant_ids[0] in request.env.user.partner_id.wishlist_ids.mapped('product_id')"/>
<a class="btn btn-default btn-xs o_add_wishlist" t-att-disabled='in_wish or None' title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
</xpath>
</template>
<template id="product_add_to_wishlist" name='Add to wishlist in product page' inherit_id="website_sale.product" priority="10">
<template id="product_add_to_wishlist" name='Add to wishlist in product page' inherit_id="website_sale.product" priority="20">
<xpath expr="//a[@id='add_to_cart']" position="after">
<t t-if="product.env.ref('website_sale_wishlist.add_to_wishlist').active">
<a class="btn btn-default btn-lg mt8 o_add_wishlist_dyn" title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
<t t-set="in_wish" t-value="product.product_variant_ids[0] in request.env.user.partner_id.wishlist_ids.mapped('product_id')"/>
<a class="btn btn-default btn-lg mt8 o_add_wishlist_dyn" t-att-disabled='in_wish or None' title="Add to Wishlist" t-att-data-product-product-id="product.product_variant_ids[0].id" data-action="o_wishlist"><span class="fa fa-heart"></span></a>
</t>
</xpath>
</template>
@@ -44,6 +46,9 @@
<div class="container oe_website_sale">
<section class="container wishlist-section">
<h3>My Wishlist</h3>
<div class="checkbox">
<label class='text-muted'><input type="checkbox" id='b2b_wish' value="1" />Add product to my cart but keep it in my wishlist</label>
</div>
<table class="table table-bordered table-striped table-hover text-center mt16 table-comparator" id="o_comparelist_table">
<body>
<t t-foreach="wishes" t-as="wish">
@@ -75,7 +80,6 @@
</td>
<td class='text-center td-wish-btn'>
<input name="product_id" t-att-value="wish.product_id.id" type="hidden"/>
<a class="btn btn-primary btn-block o_wish_mv mb4">Move <span class='hidden-xs'>to Cart</span></a>
<a class="btn btn-default btn-block o_wish_add mb4" >Add <span class='hidden-xs'>to Cart</span></a>
</td>
</tr>
+15
View File
@@ -0,0 +1,15 @@
Canada, 2017-3-24
Métal Sartigan agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Jérôme Thériault jerther@gmail.com https://github.com/jerther
List of contributors:
Jérôme Thériault jerther@gmail.com https://github.com/jerther
+15
View File
@@ -0,0 +1,15 @@
Spain, 2017-03-30
OnTruck agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Iñigo Juantegui
List of contributors:
Antonio Espinosa <antonio.espinosa@ontruck.com> https://github.com/antespi
+22
View File
@@ -0,0 +1,22 @@
Spain, 2017-04-04
Tecnativa S.L. agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Pedro M. Baeza pedro.baeza@tecnativa.com https://github.com/pedrobaeza
List of contributors:
Pedro M. Baeza pedro.baeza@tecnativa.com https://github.com/pedrobaeza
Rafael Blasco rafael.blasco@tecnativa.com https://github.com/rafaelbn
Sergio Teruel sergio.teruel@tecnativa.com https://github.com/sergio-teruel
Carlos Dauden carlos.dauden@tecnativa.com https://github.com/carlosdauden
Jairo Llopis jairo.llopis@tecnativa.com https://github.com/yajo
Vicent Cubells vicent.cubells@tecnativa.com https://github.com/cubells
Luis Montalba luis.montalba@tecnativa.com https://github.com/luismontalba
David Vidal david.vidal@tecnativa.com https://github.com/chienandalu
+4 -2
View File
@@ -1,4 +1,4 @@
Vietnam, 2016-11-30
Vietnam, 2017-04-03
T.V.T Marine Automation agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
@@ -12,4 +12,6 @@ David Tran david.tran@tvtmarine.com https://github.com/tvtma/
List of contributors:
David Tran david.tran@tvtmarine.com https://github.com/tvtma/
David Tran david.tran@tvtmarine.com https://github.com/davidtranhp
Long Do dhlong.1209@gmail.com https://github.com/hoanglong87
Hao Hoang hao.hoang@ma.tvtmarine.com https://github.com/hoanghao2001
+9
View File
@@ -0,0 +1,9 @@
Azer, 2017-03-26
I hereby agree to the terms of the Odoo Individual Contributor License Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this declaration.
Signed,
GHADHOUN AZER ezer1989@gmail.com https://github.com/monami7001
+11
View File
@@ -0,0 +1,11 @@
Vietnam, 2017-04-10
I hereby agree to the terms of the Odoo Individual Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Tran Thanh Phuc ttp.phuctran@gmail.com https://github.com/ttpphuctran
+2 -2
View File
@@ -14,7 +14,7 @@ requirement is explained in the [FAQ](#faq).
`odony`, the file would be `doc/cla/individual/odony.md`. The file should
contain:
```
```
<country>, <date>
I hereby agree to the terms of the Odoo Individual Contributor License
@@ -50,7 +50,7 @@ signature is merged.
If the name of the company is Odoo, the file would be
`doc/cla/corporate/odoo.md`. The file should contain:
```
```
<country>, <date>
<company-name> agrees to the terms of the Odoo Corporate Contributor License

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