Support global discounts in supplier invoices
This commit is contained in:
parent
2f3187c689
commit
e4d92c56b2
|
@ -1 +1,4 @@
|
|||
* Support global discounts in supplier invoices
|
||||
|
||||
Version 3.4.0 - 2016-02-17
|
||||
* Initial release
|
||||
|
|
|
@ -4,11 +4,13 @@ from trytond.pool import Pool
|
|||
from .invoice import *
|
||||
from .party import *
|
||||
|
||||
|
||||
def register():
|
||||
Pool.register(
|
||||
Party,
|
||||
Configuration,
|
||||
Invoice,
|
||||
InvoiceLine,
|
||||
Purchase,
|
||||
Sale,
|
||||
module='account_invoice_discount_global', type_='model')
|
||||
|
|
84
invoice.py
84
invoice.py
|
@ -1,10 +1,13 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from decimal import Decimal
|
||||
|
||||
from trytond.config import config
|
||||
from trytond.model import ModelView, Workflow, fields
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.config import config
|
||||
from trytond.pyson import Eval
|
||||
|
||||
__all__ = ['Configuration', 'Invoice', 'InvoiceLine', 'Sale']
|
||||
__all__ = ['Configuration', 'Invoice', 'InvoiceLine', 'Sale', 'Purchase']
|
||||
|
||||
DISCOUNT_DIGITS = int(config.get('digits', 'discount_digits', 4))
|
||||
|
||||
|
@ -36,10 +39,13 @@ class Invoice:
|
|||
def default_invoice_discount():
|
||||
return Decimal(0)
|
||||
|
||||
@fields.depends('party')
|
||||
@fields.depends('party', 'type')
|
||||
def on_change_with_invoice_discount(self):
|
||||
if self.party:
|
||||
return self.party.invoice_discount
|
||||
if self.type in ('in_invoice', 'in_credit_note'):
|
||||
return self.party.supplier_invoice_discount
|
||||
else:
|
||||
return self.party.customer_invoice_discount
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
|
@ -47,35 +53,39 @@ class Invoice:
|
|||
pool = Pool()
|
||||
Line = pool.get('account.invoice.line')
|
||||
Config = Pool().get('account.configuration')
|
||||
|
||||
config = Config(1)
|
||||
product = config.discount_product
|
||||
lines = []
|
||||
for invoice in invoices:
|
||||
if not invoice.invoice_discount:
|
||||
continue
|
||||
lines.extend(invoice._get_discount_line(invoice, product))
|
||||
lines.extend(invoice._get_discount_line(product))
|
||||
if lines:
|
||||
Line.create([x._save_values for x in lines])
|
||||
cls.update_taxes(invoices)
|
||||
|
||||
def _get_discount_line(self, invoice, product):
|
||||
def _get_discount_line(self, product):
|
||||
Line = Pool().get('account.invoice.line')
|
||||
amount = -1 * invoice.untaxed_amount * invoice.invoice_discount
|
||||
amount = -1 * self.untaxed_amount * self.invoice_discount
|
||||
lines = []
|
||||
if amount and invoice.lines:
|
||||
if amount and self.lines:
|
||||
if not product:
|
||||
self.raise_user_error('missing_discount_product',
|
||||
invoice.rec_name)
|
||||
self.rec_name)
|
||||
line = Line()
|
||||
line.invoice = self
|
||||
line.type = 'line'
|
||||
line.product = product
|
||||
line.account = product.account_revenue_used
|
||||
if self.type in ('in_invoice', 'in_credit_note'):
|
||||
line.account = product.account_expense_used
|
||||
else:
|
||||
line.account = product.account_revenue_used
|
||||
line.description = product.rec_name
|
||||
line.quantity = 1
|
||||
line.unit = product.default_uom
|
||||
line.unit_price = amount
|
||||
line._update_taxes()
|
||||
line._update_taxes(self.type, self.party)
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
|
@ -132,23 +142,36 @@ class InvoiceLine:
|
|||
__name__ = 'account.invoice.line'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
def _update_taxes(self):
|
||||
def _update_taxes(self, invoice_type, party):
|
||||
Tax = Pool().get('account.tax')
|
||||
taxes = []
|
||||
party = self.invoice.party
|
||||
pattern = self._get_tax_rule_pattern()
|
||||
for tax in self.product.customer_taxes_used:
|
||||
if party.customer_tax_rule:
|
||||
tax_ids = party.customer_tax_rule.apply(tax, pattern)
|
||||
if invoice_type in ('in_invoice', 'in_credit_note'):
|
||||
for tax in self.product.supplier_taxes_used:
|
||||
if party.supplier_tax_rule:
|
||||
tax_ids = party.supplier_tax_rule.apply(tax, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
continue
|
||||
taxes.append(tax.id)
|
||||
if party.supplier_tax_rule:
|
||||
tax_ids = party.supplier_tax_rule.apply(None, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
continue
|
||||
taxes.append(tax.id)
|
||||
if party.customer_tax_rule:
|
||||
tax_ids = party.customer_tax_rule.apply(None, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
self.taxes = Tax.browse(taxes)
|
||||
else:
|
||||
for tax in self.product.customer_taxes_used:
|
||||
if party.customer_tax_rule:
|
||||
tax_ids = party.customer_tax_rule.apply(tax, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
continue
|
||||
taxes.append(tax.id)
|
||||
if party.customer_tax_rule:
|
||||
tax_ids = party.customer_tax_rule.apply(None, pattern)
|
||||
if tax_ids:
|
||||
taxes.extend(tax_ids)
|
||||
if taxes:
|
||||
self.taxes = Tax.browse(taxes)
|
||||
|
||||
|
||||
class Sale:
|
||||
|
@ -158,5 +181,18 @@ class Sale:
|
|||
def _get_invoice_sale(self, invoice_type):
|
||||
invoice = super(Sale, self)._get_invoice_sale(invoice_type)
|
||||
if invoice:
|
||||
invoice.invoice_discount = invoice.on_change_with_invoice_discount()
|
||||
invoice.invoice_discount = (
|
||||
invoice.on_change_with_invoice_discount())
|
||||
return invoice
|
||||
|
||||
|
||||
class Purchase:
|
||||
__name__ = 'purchase.purchase'
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
def _get_invoice_purchase(self, invoice_type):
|
||||
invoice = super(Purchase, self)._get_invoice_purchase(invoice_type)
|
||||
if invoice:
|
||||
invoice.invoice_discount = (
|
||||
invoice.on_change_with_invoice_discount())
|
||||
return invoice
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="configuration_view_form">
|
||||
|
@ -6,6 +9,7 @@
|
|||
<field name="inherit" ref="account.configuration_view_form"/>
|
||||
<field name="name">configuration_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="invoice_view_form">
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="type">form</field>
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "error:account.invoice:"
|
||||
msgid "Invoice \"%s\" has a discount but no discount product is configured."
|
||||
msgstr ""
|
||||
|
@ -17,9 +16,13 @@ msgctxt "field:account.invoice,invoice_discount:"
|
|||
msgid "Invoice Discount"
|
||||
msgstr "Descompte en factura"
|
||||
|
||||
msgctxt "field:party.party,invoice_discount:"
|
||||
msgid "Invoice Discount"
|
||||
msgstr "Descompte en factura"
|
||||
msgctxt "field:party.party,customer_invoice_discount:"
|
||||
msgid "Customer Invoice Discount"
|
||||
msgstr "Descompte en factura de client"
|
||||
|
||||
msgctxt "field:party.party,supplier_invoice_discount:"
|
||||
msgid "Supplier Invoice Discount"
|
||||
msgstr "Descompte en factura de proveïdor"
|
||||
|
||||
msgctxt "view:account.invoice:"
|
||||
msgid "%"
|
||||
|
@ -28,3 +31,7 @@ msgstr "%"
|
|||
msgctxt "view:party.party:"
|
||||
msgid "%"
|
||||
msgstr "%"
|
||||
|
||||
msgctxt "view:party.party:"
|
||||
msgid "Invoice Discount"
|
||||
msgstr "Descompte en factura"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||
|
||||
|
@ -16,9 +16,13 @@ msgctxt "field:account.invoice,invoice_discount:"
|
|||
msgid "Invoice Discount"
|
||||
msgstr "Descuento en factura"
|
||||
|
||||
msgctxt "field:party.party,invoice_discount:"
|
||||
msgid "Invoice Discount"
|
||||
msgstr "Descuento en factura"
|
||||
msgctxt "field:party.party,customer_invoice_discount:"
|
||||
msgid "Customer Invoice Discount"
|
||||
msgstr "Descuento en factura de cliente"
|
||||
|
||||
msgctxt "field:party.party,supplier_invoice_discount:"
|
||||
msgid "Supplier Invoice Discount"
|
||||
msgstr "Descuento en factura de proveedor"
|
||||
|
||||
msgctxt "view:account.invoice:"
|
||||
msgid "%"
|
||||
|
@ -27,3 +31,7 @@ msgstr "%"
|
|||
msgctxt "view:party.party:"
|
||||
msgid "%"
|
||||
msgstr "%"
|
||||
|
||||
msgctxt "view:party.party:"
|
||||
msgid "Invoice Discount"
|
||||
msgstr "Descuento en factura"
|
||||
|
|
42
party.py
42
party.py
|
@ -1,6 +1,13 @@
|
|||
from trytond.model import fields
|
||||
from trytond.pool import PoolMeta
|
||||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from sql import Null
|
||||
|
||||
from trytond import backend
|
||||
from trytond.config import config
|
||||
from trytond.model import fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Eval
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['Party']
|
||||
|
||||
|
@ -10,5 +17,32 @@ DISCOUNT_DIGITS = int(config.get('digits', 'discount_digits', 4))
|
|||
class Party:
|
||||
__name__ = 'party.party'
|
||||
__metaclass__ = PoolMeta
|
||||
invoice_discount = fields.Numeric('Invoice Discount',
|
||||
digits=(16, DISCOUNT_DIGITS))
|
||||
customer_invoice_discount = fields.Property(fields.Numeric(
|
||||
'Customer Invoice Discount', digits=(16, DISCOUNT_DIGITS), states={
|
||||
'invisible': ~Eval('context', {}).get('company'),
|
||||
}))
|
||||
supplier_invoice_discount = fields.Property(fields.Numeric(
|
||||
'Supplier Invoice Discount', digits=(16, DISCOUNT_DIGITS), states={
|
||||
'invisible': ~Eval('context', {}).get('company'),
|
||||
}))
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
pool = Pool()
|
||||
Property = pool.get('ir.property')
|
||||
TableHandler = backend.get('TableHandler')
|
||||
|
||||
super(Party, cls).__register__(module_name)
|
||||
|
||||
cursor = Transaction().cursor
|
||||
handler = TableHandler(cursor, cls, module_name)
|
||||
table = cls.__table__()
|
||||
# Migration from 3.4.0: moved invoice_discount to property
|
||||
# customer_invoice_discount
|
||||
if handler.column_exist('invoice_discount'):
|
||||
cursor.execute(*table.select(table.id, table.invoice_discount,
|
||||
where=table.invoice_discount != Null))
|
||||
for party_id, invoice_discount in cursor.fetchall():
|
||||
Property.set('customer_invoice_discount', cls._name, party_id,
|
||||
invoice_discount)
|
||||
handler.drop_column('invoice_discount', exception=True)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="party_view_form">
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
================
|
||||
Invoice Scenario
|
||||
================
|
||||
================================
|
||||
Invoice Discount Global Scenario
|
||||
================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime
|
||||
>>> from dateutil.relativedelta import relativedelta
|
||||
>>> from decimal import Decimal
|
||||
|
@ -15,7 +16,7 @@ Create database::
|
|||
>>> config = config.set_trytond()
|
||||
>>> config.pool.test = True
|
||||
|
||||
Install account_invoice::
|
||||
Install account_invoice_discount_global::
|
||||
|
||||
>>> Module = Model.get('ir.module.module')
|
||||
>>> account_invoice_module, = Module.find(
|
||||
|
@ -137,10 +138,12 @@ Create tax::
|
|||
>>> tax.credit_note_tax_code = credit_note_tax_code
|
||||
>>> tax.save()
|
||||
|
||||
Create party::
|
||||
Create party with customer invoice discount of 5% and supplier discount of 3%::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> party = Party(name='Party')
|
||||
>>> party.customer_invoice_discount = Decimal('0.05')
|
||||
>>> party.supplier_invoice_discount = Decimal('0.03')
|
||||
>>> party.save()
|
||||
|
||||
Create product::
|
||||
|
@ -148,8 +151,6 @@ Create product::
|
|||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> product = Product()
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'product'
|
||||
>>> template.default_uom = unit
|
||||
|
@ -159,17 +160,12 @@ Create product::
|
|||
>>> template.account_expense = expense
|
||||
>>> template.account_revenue = revenue
|
||||
>>> template.customer_taxes.append(tax)
|
||||
>>> template.supplier_taxes.append(Tax(tax.id))
|
||||
>>> template.save()
|
||||
>>> product.template = template
|
||||
>>> product.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Create discount product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> Product = Model.get('product.product')
|
||||
>>> discount_product = Product()
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'product'
|
||||
>>> template.default_uom = unit
|
||||
|
@ -179,13 +175,12 @@ Create discount product::
|
|||
>>> template.account_expense = expense
|
||||
>>> template.account_revenue = revenue
|
||||
>>> template.save()
|
||||
>>> discount_product.template = template
|
||||
>>> discount_product.save()
|
||||
>>> discount_product, = template.products
|
||||
|
||||
Configure discount product::
|
||||
|
||||
>>> Configuration = Model.get('account.configuration')
|
||||
>>> configuration = Configuration.find([])[0]
|
||||
>>> configuration = Configuration(1)
|
||||
>>> configuration.discount_product = discount_product
|
||||
>>> configuration.save()
|
||||
|
||||
|
@ -201,13 +196,14 @@ Create payment term::
|
|||
>>> payment_term.lines.append(payment_term_line)
|
||||
>>> payment_term.save()
|
||||
|
||||
Create invoice::
|
||||
Create customer invoice::
|
||||
|
||||
>>> Invoice = Model.get('account.invoice')
|
||||
>>> InvoiceLine = Model.get('account.invoice.line')
|
||||
>>> invoice = Invoice()
|
||||
>>> invoice.party = party
|
||||
>>> invoice.payment_term = payment_term
|
||||
>>> invoice.invoice_date = today
|
||||
>>> line = InvoiceLine()
|
||||
>>> invoice.lines.append(line)
|
||||
>>> line.product = product
|
||||
|
@ -224,17 +220,82 @@ Create invoice::
|
|||
Decimal('20.00')
|
||||
>>> invoice.total_amount
|
||||
Decimal('240.00')
|
||||
>>> invoice.invoice_discount = Decimal('0.1')
|
||||
>>> invoice.save()
|
||||
|
||||
Check invoice discount is parties customer invoice discount::
|
||||
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.05')
|
||||
|
||||
Change invoice discount::
|
||||
|
||||
>>> invoice.invoice_discount = Decimal('0.1')
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('220.00')
|
||||
>>> invoice.save()
|
||||
|
||||
Post invoice and check discount is applied::
|
||||
|
||||
>>> Invoice.post([invoice.id], config.context)
|
||||
>>> invoice.reload()
|
||||
>>> invoice.state
|
||||
u'posted'
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.1')
|
||||
>>> discount_line, = [l for l in invoice.lines
|
||||
... if l.product == discount_product]
|
||||
>>> discount_line.quantity
|
||||
1.0
|
||||
>>> discount_line.amount
|
||||
Decimal('-22.00')
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('198.00')
|
||||
>>> invoice.tax_amount
|
||||
Decimal('20.00')
|
||||
>>> invoice.total_amount
|
||||
Decimal('218.00')
|
||||
|
||||
Create supplier invoice::
|
||||
|
||||
>>> invoice = Invoice()
|
||||
>>> invoice.type = 'in_invoice'
|
||||
>>> invoice.party = party
|
||||
>>> invoice.payment_term = payment_term
|
||||
>>> invoice.invoice_date = today
|
||||
>>> line = InvoiceLine()
|
||||
>>> invoice.lines.append(line)
|
||||
>>> line.product = product
|
||||
>>> line.quantity = 10
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('250.00')
|
||||
>>> invoice.tax_amount
|
||||
Decimal('25.00')
|
||||
>>> invoice.total_amount
|
||||
Decimal('275.00')
|
||||
>>> invoice.save()
|
||||
|
||||
Check invoice discount is parties supplier invoice discount::
|
||||
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.03')
|
||||
|
||||
Post invoice and check discount is applied::
|
||||
|
||||
>>> Invoice.post([invoice.id], config.context)
|
||||
>>> invoice.reload()
|
||||
>>> invoice.state
|
||||
u'posted'
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.03')
|
||||
>>> discount_line, = [l for l in invoice.lines
|
||||
... if l.product == discount_product]
|
||||
>>> discount_line.quantity
|
||||
1.0
|
||||
>>> discount_line.amount
|
||||
Decimal('-7.50')
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('242.50')
|
||||
>>> invoice.tax_amount
|
||||
Decimal('25.00')
|
||||
>>> invoice.total_amount
|
||||
Decimal('267.50')
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
=======================================================
|
||||
Invoice Discount Global from Sale and Purchase Scenario
|
||||
=======================================================
|
||||
|
||||
Imports::
|
||||
|
||||
>>> import datetime
|
||||
>>> from dateutil.relativedelta import relativedelta
|
||||
>>> from decimal import Decimal
|
||||
>>> from operator import attrgetter
|
||||
>>> from proteus import config, Model, Wizard
|
||||
>>> today = datetime.date.today()
|
||||
|
||||
Create database::
|
||||
|
||||
>>> config = config.set_trytond()
|
||||
>>> config.pool.test = True
|
||||
|
||||
Install account_invoice_discount_global, sale and purchase::
|
||||
|
||||
>>> Module = Model.get('ir.module.module')
|
||||
>>> account_invoice_module, = Module.find(
|
||||
... [('name', '=', 'account_invoice_discount_global')])
|
||||
>>> sale_module, = Module.find([('name', '=', 'sale')])
|
||||
>>> purchase_module, = Module.find([('name', '=', 'purchase')])
|
||||
>>> Module.install([
|
||||
... account_invoice_module.id,
|
||||
... sale_module.id,
|
||||
... purchase_module.id,
|
||||
... ], config.context)
|
||||
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
|
||||
|
||||
Create company::
|
||||
|
||||
>>> Currency = Model.get('currency.currency')
|
||||
>>> CurrencyRate = Model.get('currency.currency.rate')
|
||||
>>> currencies = Currency.find([('code', '=', 'USD')])
|
||||
>>> if not currencies:
|
||||
... currency = Currency(name='U.S. Dollar', symbol='$', code='USD',
|
||||
... rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
|
||||
... mon_decimal_point='.', mon_thousands_sep=',')
|
||||
... currency.save()
|
||||
... CurrencyRate(date=today + relativedelta(month=1, day=1),
|
||||
... rate=Decimal('1.0'), currency=currency).save()
|
||||
... else:
|
||||
... currency, = currencies
|
||||
>>> Company = Model.get('company.company')
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> company_config = Wizard('company.company.config')
|
||||
>>> company_config.execute('company')
|
||||
>>> company = company_config.form
|
||||
>>> party = Party(name='Dunder Mifflin')
|
||||
>>> party.save()
|
||||
>>> company.party = party
|
||||
>>> company.currency = currency
|
||||
>>> company_config.execute('add')
|
||||
>>> company, = Company.find([])
|
||||
|
||||
Reload the context::
|
||||
|
||||
>>> User = Model.get('res.user')
|
||||
>>> Group = Model.get('res.group')
|
||||
>>> config._context = User.get_preferences(True, config.context)
|
||||
|
||||
Create sale user::
|
||||
|
||||
>>> sale_user = User()
|
||||
>>> sale_user.name = 'Sale'
|
||||
>>> sale_user.login = 'sale'
|
||||
>>> sale_user.main_company = company
|
||||
>>> sale_group, = Group.find([('name', '=', 'Sales')])
|
||||
>>> sale_user.groups.append(sale_group)
|
||||
>>> sale_user.save()
|
||||
|
||||
Create stock user::
|
||||
|
||||
>>> stock_user = User()
|
||||
>>> stock_user.name = 'Stock'
|
||||
>>> stock_user.login = 'stock'
|
||||
>>> stock_user.main_company = company
|
||||
>>> stock_group, = Group.find([('name', '=', 'Stock')])
|
||||
>>> stock_user.groups.append(stock_group)
|
||||
>>> stock_user.save()
|
||||
|
||||
Create account user::
|
||||
|
||||
>>> account_user = User()
|
||||
>>> account_user.name = 'Account'
|
||||
>>> account_user.login = 'account'
|
||||
>>> account_user.main_company = company
|
||||
>>> account_group, = Group.find([('name', '=', 'Account')])
|
||||
>>> account_user.groups.append(account_group)
|
||||
>>> account_user.save()
|
||||
|
||||
Create fiscal year::
|
||||
|
||||
>>> FiscalYear = Model.get('account.fiscalyear')
|
||||
>>> Sequence = Model.get('ir.sequence')
|
||||
>>> SequenceStrict = Model.get('ir.sequence.strict')
|
||||
>>> fiscalyear = FiscalYear(name=str(today.year))
|
||||
>>> fiscalyear.start_date = today + relativedelta(month=1, day=1)
|
||||
>>> fiscalyear.end_date = today + relativedelta(month=12, day=31)
|
||||
>>> fiscalyear.company = company
|
||||
>>> post_move_seq = Sequence(name=str(today.year), code='account.move',
|
||||
... company=company)
|
||||
>>> post_move_seq.save()
|
||||
>>> fiscalyear.post_move_sequence = post_move_seq
|
||||
>>> invoice_seq = SequenceStrict(name=str(today.year),
|
||||
... code='account.invoice', company=company)
|
||||
>>> invoice_seq.save()
|
||||
>>> fiscalyear.out_invoice_sequence = invoice_seq
|
||||
>>> fiscalyear.in_invoice_sequence = invoice_seq
|
||||
>>> fiscalyear.out_credit_note_sequence = invoice_seq
|
||||
>>> fiscalyear.in_credit_note_sequence = invoice_seq
|
||||
>>> fiscalyear.save()
|
||||
>>> FiscalYear.create_period([fiscalyear.id], config.context)
|
||||
|
||||
Create chart of accounts::
|
||||
|
||||
>>> AccountTemplate = Model.get('account.account.template')
|
||||
>>> Account = Model.get('account.account')
|
||||
>>> Journal = Model.get('account.journal')
|
||||
>>> account_template, = AccountTemplate.find([('parent', '=', None)])
|
||||
>>> create_chart = Wizard('account.create_chart')
|
||||
>>> create_chart.execute('account')
|
||||
>>> create_chart.form.account_template = account_template
|
||||
>>> create_chart.form.company = company
|
||||
>>> create_chart.execute('create_account')
|
||||
>>> receivable, = Account.find([
|
||||
... ('kind', '=', 'receivable'),
|
||||
... ('company', '=', company.id),
|
||||
... ])
|
||||
>>> payable, = Account.find([
|
||||
... ('kind', '=', 'payable'),
|
||||
... ('company', '=', company.id),
|
||||
... ])
|
||||
>>> revenue, = Account.find([
|
||||
... ('kind', '=', 'revenue'),
|
||||
... ('company', '=', company.id),
|
||||
... ])
|
||||
>>> expense, = Account.find([
|
||||
... ('kind', '=', 'expense'),
|
||||
... ('company', '=', company.id),
|
||||
... ])
|
||||
>>> account_tax, = Account.find([
|
||||
... ('kind', '=', 'other'),
|
||||
... ('company', '=', company.id),
|
||||
... ('name', '=', 'Main Tax'),
|
||||
... ])
|
||||
>>> create_chart.form.account_receivable = receivable
|
||||
>>> create_chart.form.account_payable = payable
|
||||
>>> create_chart.execute('create_properties')
|
||||
|
||||
Create tax::
|
||||
|
||||
>>> TaxCode = Model.get('account.tax.code')
|
||||
>>> Tax = Model.get('account.tax')
|
||||
>>> tax = Tax()
|
||||
>>> tax.name = 'Tax'
|
||||
>>> tax.description = 'Tax'
|
||||
>>> tax.type = 'percentage'
|
||||
>>> tax.rate = Decimal('.10')
|
||||
>>> tax.invoice_account = account_tax
|
||||
>>> tax.credit_note_account = account_tax
|
||||
>>> invoice_base_code = TaxCode(name='invoice base')
|
||||
>>> invoice_base_code.save()
|
||||
>>> tax.invoice_base_code = invoice_base_code
|
||||
>>> invoice_tax_code = TaxCode(name='invoice tax')
|
||||
>>> invoice_tax_code.save()
|
||||
>>> tax.invoice_tax_code = invoice_tax_code
|
||||
>>> credit_note_base_code = TaxCode(name='credit note base')
|
||||
>>> credit_note_base_code.save()
|
||||
>>> tax.credit_note_base_code = credit_note_base_code
|
||||
>>> credit_note_tax_code = TaxCode(name='credit note tax')
|
||||
>>> credit_note_tax_code.save()
|
||||
>>> tax.credit_note_tax_code = credit_note_tax_code
|
||||
>>> tax.save()
|
||||
|
||||
Create parties::
|
||||
|
||||
>>> Party = Model.get('party.party')
|
||||
>>> supplier = Party(name='Supplier')
|
||||
>>> supplier.supplier_invoice_discount = Decimal('0.03')
|
||||
>>> supplier.save()
|
||||
>>> customer = Party(name='Customer')
|
||||
>>> customer.customer_invoice_discount = Decimal('0.05')
|
||||
>>> customer.save()
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||
>>> ProductTemplate = Model.get('product.template')
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'service'
|
||||
>>> template.purchasable = True
|
||||
>>> template.salable = True
|
||||
>>> template.list_price = Decimal('40')
|
||||
>>> template.cost_price = Decimal('25')
|
||||
>>> template.account_expense = expense
|
||||
>>> template.account_revenue = revenue
|
||||
>>> template.customer_taxes.append(tax)
|
||||
>>> template.supplier_taxes.append(Tax(tax.id))
|
||||
>>> template.save()
|
||||
>>> product, = template.products
|
||||
|
||||
Create discount product::
|
||||
|
||||
>>> template = ProductTemplate()
|
||||
>>> template.name = 'product'
|
||||
>>> template.default_uom = unit
|
||||
>>> template.type = 'service'
|
||||
>>> template.list_price = Decimal('0')
|
||||
>>> template.cost_price = Decimal('0')
|
||||
>>> template.account_expense = expense
|
||||
>>> template.account_revenue = revenue
|
||||
>>> template.save()
|
||||
>>> discount_product, = template.products
|
||||
|
||||
Configure discount product::
|
||||
|
||||
>>> Configuration = Model.get('account.configuration')
|
||||
>>> configuration = Configuration(1)
|
||||
>>> configuration.discount_product = discount_product
|
||||
>>> configuration.save()
|
||||
|
||||
Create payment term::
|
||||
|
||||
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||
>>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
|
||||
>>> payment_term = PaymentTerm(name='Direct')
|
||||
>>> payment_term_line = PaymentTermLine(type='remainder', days=0)
|
||||
>>> payment_term.lines.append(payment_term_line)
|
||||
>>> payment_term.save()
|
||||
|
||||
Sale 5 services::
|
||||
|
||||
>>> Sale = Model.get('sale.sale')
|
||||
>>> SaleLine = Model.get('sale.line')
|
||||
>>> sale = Sale()
|
||||
>>> sale.party = customer
|
||||
>>> sale.payment_term = payment_term
|
||||
>>> sale.invoice_method = 'order'
|
||||
>>> sale_line = SaleLine()
|
||||
>>> sale.lines.append(sale_line)
|
||||
>>> sale_line.product = product
|
||||
>>> sale_line.quantity = 5.0
|
||||
>>> sale.save()
|
||||
>>> Sale.quote([sale.id], config.context)
|
||||
>>> Sale.confirm([sale.id], config.context)
|
||||
>>> Sale.process([sale.id], config.context)
|
||||
>>> sale.state
|
||||
u'processing'
|
||||
>>> sale.reload()
|
||||
>>> sale.untaxed_amount
|
||||
Decimal('200.00')
|
||||
>>> sale.tax_amount
|
||||
Decimal('20.00')
|
||||
>>> sale.total_amount
|
||||
Decimal('220.00')
|
||||
>>> len(sale.shipments), len(sale.shipment_returns), len(sale.invoices)
|
||||
(0, 0, 1)
|
||||
>>> invoice, = sale.invoices
|
||||
>>> invoice.origins == sale.rec_name
|
||||
True
|
||||
|
||||
Created invoice has customer's invoice discount::
|
||||
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.05')
|
||||
|
||||
Post invoice and check discount is applied::
|
||||
|
||||
>>> Invoice = Model.get('account.invoice')
|
||||
>>> Invoice.post([i.id for i in sale.invoices], config.context)
|
||||
>>> invoice.reload()
|
||||
>>> discount_line, = [l for l in invoice.lines
|
||||
... if l.product == discount_product]
|
||||
>>> discount_line.quantity
|
||||
1.0
|
||||
>>> discount_line.amount
|
||||
Decimal('-10.00')
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('190.00')
|
||||
>>> invoice.tax_amount
|
||||
Decimal('20.00')
|
||||
>>> invoice.total_amount
|
||||
Decimal('210.00')
|
||||
|
||||
Purchase 3 services::
|
||||
|
||||
>>> Purchase = Model.get('purchase.purchase')
|
||||
>>> PurchaseLine = Model.get('purchase.line')
|
||||
>>> purchase = Purchase()
|
||||
>>> purchase.party = supplier
|
||||
>>> purchase.payment_term = payment_term
|
||||
>>> purchase.invoice_method = 'order'
|
||||
>>> purchase_line = PurchaseLine()
|
||||
>>> purchase.lines.append(purchase_line)
|
||||
>>> purchase_line.product = product
|
||||
>>> purchase_line.quantity = 3.0
|
||||
>>> purchase.click('quote')
|
||||
>>> purchase.click('confirm')
|
||||
>>> purchase.click('process')
|
||||
>>> purchase.state
|
||||
u'processing'
|
||||
>>> purchase.reload()
|
||||
>>> purchase.untaxed_amount
|
||||
Decimal('75.00')
|
||||
>>> purchase.tax_amount
|
||||
Decimal('7.50')
|
||||
>>> purchase.total_amount
|
||||
Decimal('82.50')
|
||||
>>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
|
||||
(0, 0, 1)
|
||||
>>> invoice, = purchase.invoices
|
||||
>>> invoice.origins == purchase.rec_name
|
||||
True
|
||||
|
||||
Created invoice has supplier's invoice discount::
|
||||
|
||||
>>> invoice.invoice_discount
|
||||
Decimal('0.03')
|
||||
|
||||
Post invoice and check discount is applied::
|
||||
|
||||
>>> invoice.invoice_date = today
|
||||
>>> invoice.save()
|
||||
>>> Invoice.post([invoice.id], config.context)
|
||||
>>> invoice.reload()
|
||||
>>> discount_line, = [l for l in invoice.lines
|
||||
... if l.product == discount_product]
|
||||
>>> discount_line.quantity
|
||||
1.0
|
||||
>>> discount_line.amount
|
||||
Decimal('-2.25')
|
||||
>>> invoice.untaxed_amount
|
||||
Decimal('72.75')
|
||||
>>> invoice.tax_amount
|
||||
Decimal('7.50')
|
||||
>>> invoice.total_amount
|
||||
Decimal('80.25')
|
|
@ -1,14 +1,15 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
import unittest
|
||||
import doctest
|
||||
import unittest
|
||||
|
||||
import trytond.tests.test_tryton
|
||||
from trytond.tests.test_tryton import test_view, test_depends
|
||||
from trytond.tests.test_tryton import doctest_setup, doctest_teardown
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
'Test module'
|
||||
'Test account_invoice_discount_global module'
|
||||
|
||||
def setUp(self):
|
||||
trytond.tests.test_tryton.install_module(
|
||||
|
@ -29,4 +30,7 @@ def suite():
|
|||
suite.addTests(doctest.DocFileSuite('scenario_invoice.rst',
|
||||
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
suite.addTests(doctest.DocFileSuite('scenario_invoice_sale_purchase.rst',
|
||||
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
|
||||
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||
return suite
|
|
@ -1,8 +1,10 @@
|
|||
[tryton]
|
||||
version=3.4.0
|
||||
version=3.4.1
|
||||
depends:
|
||||
account_invoice
|
||||
extras_depend:
|
||||
sale
|
||||
purchase
|
||||
xml:
|
||||
invoice.xml
|
||||
party.xml
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/field[@name='default_account_payable']" position="after">
|
||||
<label name="discount_product"/>
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/notebook/page[@id='invoice']/field[@name='currency']" position="after">
|
||||
<xpath expr="/form/notebook/page[@id='invoice']/field[@name='currency']"
|
||||
position="after">
|
||||
<label name="invoice_discount"/>
|
||||
<group id="discount" col="2" xexpand="0">
|
||||
<field name="invoice_discount" factor="100" xalign="1.0" xexpand="0"/>
|
||||
<label name="invoice_discount" string="%" xalign="0.0" xexpand="1" xfill="1"/>
|
||||
<field name="invoice_discount" factor="100"
|
||||
xalign="1.0" xexpand="0"/>
|
||||
<label name="invoice_discount" string="%"
|
||||
xalign="0.0" xexpand="1" xfill="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
</data>
|
|
@ -1,9 +1,23 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/notebook/page[@id='sale']" position="inside">
|
||||
<label name="invoice_discount"/>
|
||||
<group id="discount" col="2" xexpand="0">
|
||||
<field name="invoice_discount" factor="100" xalign="1.0" xexpand="0"/>
|
||||
<label name="invoice_discount" string="%" xalign="0.0" xexpand="1" xfill="1"/>
|
||||
<xpath expr="/form/notebook/page[@id='accounting']/field[@name='vat_number']"
|
||||
position="after">
|
||||
<separator string="Invoice Discount" colspan="4" id="invoice_discount"/>
|
||||
<label name="customer_invoice_discount"/>
|
||||
<group id="customer_invoice_discount" col="2" xexpand="0">
|
||||
<field name="customer_invoice_discount" factor="100"
|
||||
xalign="1.0" xexpand="0"/>
|
||||
<label name="customer_invoice_discount" string="%"
|
||||
xalign="0.0" xexpand="1" xfill="1"/>
|
||||
</group>
|
||||
<label name="supplier_invoice_discount"/>
|
||||
<group id="supplier_invoice_discount" col="2" xexpand="0">
|
||||
<field name="supplier_invoice_discount" factor="100"
|
||||
xalign="1.0" xexpand="0"/>
|
||||
<label name="supplier_invoice_discount" string="%"
|
||||
xalign="0.0" xexpand="1" xfill="1"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
</data>
|
Loading…
Reference in New Issue