fix and tests
This commit is contained in:
parent
f2b8ee4488
commit
e9ac5b4b50
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from template import *
|
from template import *
|
||||||
|
from invoice import *
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
Pool.register(
|
Pool.register(
|
||||||
Template,
|
Template,
|
||||||
|
InvoiceLine,
|
||||||
module='account_invoice_information_uom', type_='model')
|
module='account_invoice_information_uom', type_='model')
|
||||||
|
|
68
invoice.py
68
invoice.py
|
@ -1,21 +1,24 @@
|
||||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
import datetime
|
|
||||||
|
|
||||||
from trytond.model import ModelView, ModelSQL, fields
|
from trytond.model import fields
|
||||||
from trytond.pyson import Eval, If
|
from trytond.pyson import Eval, If
|
||||||
from trytond.pool import Pool, PoolMeta
|
from trytond.pool import PoolMeta
|
||||||
from trytond.transaction import Transaction
|
|
||||||
from trytond import backend
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
__all__ = ['InvoiceLine']
|
||||||
|
__metaclass__ = PoolMeta
|
||||||
|
|
||||||
|
_ZERO = Decimal('0.0')
|
||||||
|
_ROUND = Decimal('.0001')
|
||||||
|
|
||||||
|
|
||||||
class InvoiceLine:
|
class InvoiceLine:
|
||||||
__name__ = 'account.invoce.line'
|
__name__ = 'account.invoice.line'
|
||||||
|
|
||||||
info_unit = fields.Function(fields.Many2One('product.uom',
|
info_unit = fields.Function(fields.Many2One('product.uom',
|
||||||
'Information UOM',
|
'Information UOM',
|
||||||
on_change_with=['product']), 'get_info_unit')
|
on_change_with=['product']), 'on_change_with_info_unit')
|
||||||
info_unit_digits = fields.Function(fields.Integer(
|
info_unit_digits = fields.Function(fields.Integer(
|
||||||
'Information Unit Digits', on_change_with=['info_unit']),
|
'Information Unit Digits', on_change_with=['info_unit']),
|
||||||
'on_change_with_unit_digits')
|
'on_change_with_unit_digits')
|
||||||
|
@ -26,18 +29,22 @@ class InvoiceLine:
|
||||||
'invisible': Eval('type') != 'line',
|
'invisible': Eval('type') != 'line',
|
||||||
'required': Eval('type') == 'line',
|
'required': Eval('type') == 'line',
|
||||||
},
|
},
|
||||||
on_change_with=['quantity', 'product', 'info_quantity'],
|
on_change_with=['quantity', 'product', 'info_quantity',
|
||||||
on_change=['quantity', 'unit_quantity', 'info_quantity']
|
'info_unit_price', 'product'],
|
||||||
depends=['type', 'info_unit_digits'])
|
on_change=['quantity', 'unit_quantity', 'unit',
|
||||||
|
'info_quantity', 'info_unit_price', 'product'],
|
||||||
|
depends=['type', 'info_unit_digits', 'product', 'unit', 'unit_digits'])
|
||||||
|
|
||||||
info_unit_price = fields.Numeric('Information Unit Price', digits=(16, 4),
|
info_unit_price = fields.Numeric('Information Unit Price', digits=(16, 4),
|
||||||
states={
|
states={
|
||||||
'invisible': Eval('type') != 'line',
|
'invisible': Eval('type') != 'line',
|
||||||
'required': Eval('type') == 'line',
|
'required': Eval('type') == 'line',
|
||||||
},
|
},
|
||||||
on_change=['unit_price', 'invoice_type']
|
on_change=['info_unit_price', 'invoice_type', 'product', 'info_quantity',
|
||||||
on_change_with=['unit_price', 'type', 'invoice_type', 'product'],
|
'invoice_type', 'type'],
|
||||||
depends=['type', 'invoice_type'])
|
on_change_with=['unit_price', 'type', 'invoice_type',
|
||||||
|
'info_unit_price', 'info_quantity', 'product', 'unit_price'],
|
||||||
|
depends=['type', 'invoice_type', 'product'])
|
||||||
|
|
||||||
info_amount = fields.Function(fields.Numeric('Information Amount',
|
info_amount = fields.Function(fields.Numeric('Information Amount',
|
||||||
digits=(16, Eval('_parent_invoice', {}).get('currency_digits',
|
digits=(16, Eval('_parent_invoice', {}).get('currency_digits',
|
||||||
|
@ -45,15 +52,10 @@ class InvoiceLine:
|
||||||
states={
|
states={
|
||||||
'invisible': ~Eval('type').in_(['line', 'subtotal']),
|
'invisible': ~Eval('type').in_(['line', 'subtotal']),
|
||||||
},
|
},
|
||||||
on_change_with=['type', 'quantity', 'unit_price', 'info_quantity',
|
on_change_with=['type', 'info_unit_price',
|
||||||
'_parent_invoice.currency', 'currency'],
|
'info_quantity', '_parent_invoice.currency', 'currency'],
|
||||||
depends=['type', 'currency_digits']), 'get_amount')
|
depends=['type', 'currency_digits']), 'get_amount')
|
||||||
|
|
||||||
def get_info_unit(self):
|
|
||||||
if self.product and self.product.use_info_unit:
|
|
||||||
return self.product.info_unit.id
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_info_unit_digits():
|
def default_info_unit_digits():
|
||||||
return 2
|
return 2
|
||||||
|
@ -64,31 +66,43 @@ class InvoiceLine:
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def on_change_with_info_unit(self, name=None):
|
def on_change_with_info_unit(self, name=None):
|
||||||
if not self.product or not self.product.use_info_unit:
|
if (self.product and self.product.use_info_unit and
|
||||||
return None
|
self.product.info_unit):
|
||||||
return self.product.info_unit.id
|
return self.product.info_unit.id
|
||||||
|
return None
|
||||||
|
|
||||||
def on_change_with_info_quantity(self, name=None):
|
def on_change_with_info_quantity(self, name=None):
|
||||||
if not self.product:
|
if not self.product or not self.quantity:
|
||||||
return
|
return
|
||||||
return self.product.calc_info_quantity(self.qty)
|
return self.product.calc_info_quantity(self.quantity)
|
||||||
|
|
||||||
def on_change_info_quantity(self, name=None):
|
def on_change_info_quantity(self, name=None):
|
||||||
if not self.product:
|
if not self.product:
|
||||||
return {}
|
return {}
|
||||||
|
qty = self.product.calc_quantity(
|
||||||
|
self.info_quantity, self.unit)
|
||||||
return {
|
return {
|
||||||
'qty': self.product.calc_info_quantity(self.info_qty, self.unit)
|
'quantity': float(qty)
|
||||||
}
|
}
|
||||||
|
|
||||||
def on_change_with_info_unit_price(self, name=None):
|
def on_change_with_info_unit_price(self, name=None):
|
||||||
if not self.product:
|
if not self.product:
|
||||||
return
|
return
|
||||||
return self.product.get_unit_price(self.info_unit_price)
|
if not self.unit_price:
|
||||||
|
return
|
||||||
|
if self.type in ('out_invoice', 'out_refund'):
|
||||||
|
return self.product.get_info_list_price(self.unit_price)
|
||||||
|
else:
|
||||||
|
return self.product.get_info_cost_price(self.unit_price)
|
||||||
|
|
||||||
def on_change_info_unit_price(self, name=None):
|
def on_change_info_unit_price(self, name=None):
|
||||||
if not self.product:
|
if not self.product:
|
||||||
return {}
|
return {}
|
||||||
|
if not self.info_unit_price:
|
||||||
|
return {}
|
||||||
return {
|
return {
|
||||||
'qty': self.product.calc_info_quantity(self.info_qty, self.unit)
|
'unit_price': self.product.get_unit_price(self.info_unit_price)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def on_change_with_info_amount(self, name=None):
|
||||||
|
return self.info_unit_price * self.info_quantity
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?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. -->
|
||||||
|
<tryton>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="invoice_line_view_form">
|
||||||
|
<field name="model">account.invoice.line</field>
|
||||||
|
<field name="inherit" ref="account_invoice.invoice_line_view_form"/>
|
||||||
|
<field name="name">invoice_line_form</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.ui.view" id="invoice_line_view_tree">
|
||||||
|
<field name="model">account.invoice.line</field>
|
||||||
|
<field name="inherit" ref="account_invoice.invoice_line_view_tree"/>
|
||||||
|
<field name="name">invoice_line_tree</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</tryton>
|
51
template.py
51
template.py
|
@ -3,11 +3,12 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from trytond.model import ModelView, ModelSQL, fields
|
from trytond.model import ModelView, ModelSQL, fields
|
||||||
from trytond.pyson import Eval, If
|
from trytond.pyson import Eval, Bool
|
||||||
from trytond.pool import Pool, PoolMeta
|
from trytond.pool import Pool, PoolMeta
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond import backend
|
from trytond import backend
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
import sys
|
||||||
|
|
||||||
__all__ = ['Template']
|
__all__ = ['Template']
|
||||||
__metaclass__ = PoolMeta
|
__metaclass__ = PoolMeta
|
||||||
|
@ -15,13 +16,16 @@ __metaclass__ = PoolMeta
|
||||||
_ZERO = Decimal('0.0')
|
_ZERO = Decimal('0.0')
|
||||||
_ROUND = Decimal('.0001')
|
_ROUND = Decimal('.0001')
|
||||||
|
|
||||||
|
|
||||||
class Template:
|
class Template:
|
||||||
__name__ = "product.template"
|
__name__ = "product.template"
|
||||||
|
|
||||||
use_info_unit = fields.Boolean('Use Information UOM')
|
use_info_unit = fields.Boolean('Use Information UOM')
|
||||||
info_unit = fields.Many2One('product.uom', 'Information UOM')
|
info_unit = fields.Many2One('product.uom', 'Information UOM',
|
||||||
|
states={'required': Bool(Eval('use_info_unit'))})
|
||||||
info_list_price = fields.Function(fields.Numeric('Information List Price',
|
info_list_price = fields.Function(fields.Numeric('Information List Price',
|
||||||
digits=(16, 8), on_change=['list_price', 'info_list_price',
|
digits=(16, 8),
|
||||||
|
on_change=['list_price', 'info_list_price',
|
||||||
'info_ratio', 'use_info_unit'],
|
'info_ratio', 'use_info_unit'],
|
||||||
on_change_with=['info_ratio', 'list_price', 'use_info_unit']),
|
on_change_with=['info_ratio', 'list_price', 'use_info_unit']),
|
||||||
'on_change_with_info_list_price', setter='set_info_list_price')
|
'on_change_with_info_list_price', setter='set_info_list_price')
|
||||||
|
@ -30,36 +34,37 @@ class Template:
|
||||||
'info_ratio', 'use_info_unit'],
|
'info_ratio', 'use_info_unit'],
|
||||||
on_change_with=['info_ratio', 'cost_price', 'use_info_unit']),
|
on_change_with=['info_ratio', 'cost_price', 'use_info_unit']),
|
||||||
'on_change_with_info_cost_price', setter='set_info_cost_price')
|
'on_change_with_info_cost_price', setter='set_info_cost_price')
|
||||||
info_ratio = fields.Numeric('Information Ratio', digits=(16, 4))
|
info_ratio = fields.Numeric('Information Ratio', digits=(16, 4),
|
||||||
|
states={'required': Bool(Eval('use_info_unit'))})
|
||||||
|
|
||||||
def calc_info_quantity(self, qty):
|
def calc_info_quantity(self, qty):
|
||||||
if self.use_info_unit:
|
if not self.use_info_unit:
|
||||||
return _ZERO
|
return _ZERO
|
||||||
|
info_qty = self.info_ratio * Decimal(str(qty))
|
||||||
Uom = Pool().get('product.uom')
|
print "a:", info_qty
|
||||||
info_qty = self.info_ratio * qty
|
return info_qty
|
||||||
return Uom.compute_qty([self], self.info_unit, info_qty)
|
|
||||||
|
|
||||||
def calc_quantity(self, info_qty, uom):
|
def calc_quantity(self, info_qty, uom):
|
||||||
if self.use_info_unit:
|
if not self.use_info_unit:
|
||||||
return _ZERO
|
return _ZERO
|
||||||
Uom = Pool().get('product.uom')
|
Uom = Pool().get('product.uom')
|
||||||
qty = info_qty / self.info_ratio
|
qty = info_qty / self.info_ratio
|
||||||
return Uom.compute_qty([self], uom, qty)
|
return (qty).quantize(_ROUND)
|
||||||
|
|
||||||
def get_info_list_price(self):
|
def get_info_list_price(self):
|
||||||
if self.use_info_uom:
|
if self.use_info_unit and self.info_ratio and self.list_price:
|
||||||
return (self.info_ratio * self.list_price).quantize(_ROUND)
|
return (self.info_ratio * self.list_price).quantize(_ROUND)
|
||||||
return _ZERO
|
return _ZERO
|
||||||
|
|
||||||
def get_info_cost_price(self):
|
def get_info_cost_price(self, value=None):
|
||||||
if self.use_info_uom:
|
if not value:
|
||||||
return (self.info_ratio * self.cost_price).quantize(_ROUND)
|
value = self.cost_price
|
||||||
|
if self.use_info_unit and self.info_ratio and self.cost_price:
|
||||||
|
return (self.info_ratio * value).quantize(_ROUND)
|
||||||
return _ZERO
|
return _ZERO
|
||||||
|
|
||||||
def get_unit_price(self, info_price):
|
def get_unit_price(self, info_price):
|
||||||
if self.use_info_uom:
|
if self.use_info_unit:
|
||||||
return (info_price / self.info_ratio).quantize(_ROUND)
|
return (info_price / self.info_ratio).quantize(_ROUND)
|
||||||
return _ZERO
|
return _ZERO
|
||||||
|
|
||||||
|
@ -81,13 +86,19 @@ class Template:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_info_list_price(cls, templates, name, value):
|
def set_info_list_price(cls, templates, name, value):
|
||||||
|
print >> sys.stderr, "hola:", templates, name, value
|
||||||
|
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
for template in templates:
|
for template in templates:
|
||||||
template.list_price = template.get_list_price(value)
|
template.list_price = template.get_unit_price(value)
|
||||||
template.save()
|
template.save()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_info_cost_price(cls, templates, name, value):
|
def set_info_cost_price(cls, templates, name, value):
|
||||||
|
print >> sys.stderr, "hola2:", templates, name, value
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
for template in templates:
|
for template in templates:
|
||||||
template.cost_price = template.get_cost_price(value)
|
template.cost_price = template.get_unit_price(value)
|
||||||
template.save()
|
template.save()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
=========================
|
||||||
|
Invoice Supplier 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::
|
||||||
|
|
||||||
|
>>> Module = Model.get('ir.module.module')
|
||||||
|
>>> account_invoice_module, = Module.find(
|
||||||
|
... [('name', '=', 'account_invoice_information_uom')])
|
||||||
|
>>> Module.install([account_invoice_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='US Dollar', symbol=u'$', code='USD',
|
||||||
|
... rounding=Decimal('0.01'), mon_grouping='[]',
|
||||||
|
... mon_decimal_point='.')
|
||||||
|
... 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')
|
||||||
|
>>> config._context = User.get_preferences(True, config.context)
|
||||||
|
|
||||||
|
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')
|
||||||
|
>>> 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 party::
|
||||||
|
|
||||||
|
>>> Party = Model.get('party.party')
|
||||||
|
>>> party = Party(name='Party')
|
||||||
|
>>> party.save()
|
||||||
|
|
||||||
|
Create product::
|
||||||
|
|
||||||
|
>>> ProductUom = Model.get('product.uom')
|
||||||
|
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
|
||||||
|
>>> unit2, = ProductUom.find([('name', '=', 'Kilogram')])
|
||||||
|
>>> ProductTemplate = Model.get('product.template')
|
||||||
|
>>> Product = Model.get('product.product')
|
||||||
|
>>> product = Product()
|
||||||
|
>>> template = ProductTemplate()
|
||||||
|
>>> template.name = 'product'
|
||||||
|
>>> template.default_uom = unit
|
||||||
|
>>> template.use_info_unit = True
|
||||||
|
>>> template.info_unit = unit2
|
||||||
|
>>> template.info_ratio = Decimal('2')
|
||||||
|
>>> template.type = 'service'
|
||||||
|
>>> template.list_price = Decimal('40')
|
||||||
|
>>> template.cost_price = Decimal('20')
|
||||||
|
>>> template.account_expense = expense
|
||||||
|
>>> template.account_revenue = revenue
|
||||||
|
>>> template.supplier_taxes.append(tax)
|
||||||
|
>>> template.info_cost_price
|
||||||
|
Decimal('40.0000')
|
||||||
|
>>> template.info_list_price
|
||||||
|
Decimal('80.0000')
|
||||||
|
>>> template.info_cost_price
|
||||||
|
Decimal('40.0000')
|
||||||
|
>>> product.template = template
|
||||||
|
>>> product.save()
|
||||||
|
|
||||||
|
Create payment term::
|
||||||
|
|
||||||
|
>>> PaymentTerm = Model.get('account.invoice.payment_term')
|
||||||
|
>>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
|
||||||
|
>>> payment_term = PaymentTerm(name='Term')
|
||||||
|
>>> payment_term_line = PaymentTermLine(type='remainder')
|
||||||
|
>>> payment_term.lines.append(payment_term_line)
|
||||||
|
>>> payment_term.save()
|
||||||
|
|
||||||
|
Create invoice::
|
||||||
|
|
||||||
|
>>> Invoice = Model.get('account.invoice')
|
||||||
|
>>> InvoiceLine = Model.get('account.invoice.line')
|
||||||
|
>>> 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 = 5
|
||||||
|
>>> line = InvoiceLine()
|
||||||
|
>>> invoice.lines.append(line)
|
||||||
|
>>> line.account = expense
|
||||||
|
>>> line.description = 'Test'
|
||||||
|
>>> line.quantity = 1
|
||||||
|
>>> line.unit_price = Decimal(10)
|
||||||
|
>>> invoice.untaxed_amount == Decimal(110)
|
||||||
|
True
|
||||||
|
>>> invoice.tax_amount == Decimal(10)
|
||||||
|
True
|
||||||
|
>>> invoice.total_amount == Decimal(120)
|
||||||
|
True
|
||||||
|
>>> invoice.save()
|
||||||
|
>>> Invoice.post([invoice.id], config.context)
|
||||||
|
>>> invoice.reload()
|
||||||
|
>>> invoice.state
|
||||||
|
u'posted'
|
||||||
|
>>> invoice.untaxed_amount == Decimal(110)
|
||||||
|
True
|
||||||
|
>>> invoice.tax_amount == Decimal(10)
|
||||||
|
True
|
||||||
|
>>> invoice.total_amount == Decimal(120)
|
||||||
|
True
|
||||||
|
>>> payable.reload()
|
||||||
|
>>> (payable.debit, payable.credit) == \
|
||||||
|
... (Decimal(0), Decimal(120))
|
||||||
|
True
|
||||||
|
>>> expense.reload()
|
||||||
|
>>> (expense.debit, expense.credit) == \
|
||||||
|
... (Decimal(110), Decimal(0))
|
||||||
|
True
|
||||||
|
>>> account_tax.reload()
|
||||||
|
>>> (account_tax.debit, account_tax.credit) == \
|
||||||
|
... (Decimal(10), Decimal(0))
|
||||||
|
True
|
||||||
|
>>> invoice_base_code.reload()
|
||||||
|
>>> invoice_base_code.sum == Decimal(100)
|
||||||
|
True
|
||||||
|
>>> invoice_tax_code.reload()
|
||||||
|
>>> invoice_tax_code.sum == Decimal(10)
|
||||||
|
True
|
||||||
|
>>> credit_note_base_code.reload()
|
||||||
|
>>> credit_note_base_code.sum == Decimal(0)
|
||||||
|
True
|
||||||
|
>>> credit_note_tax_code.reload()
|
||||||
|
>>> credit_note_tax_code.sum == Decimal(0)
|
||||||
|
True
|
||||||
|
|
||||||
|
Credit invoice::
|
||||||
|
|
||||||
|
>>> credit = Wizard('account.invoice.credit', [invoice])
|
||||||
|
>>> credit.form.with_refund = False
|
||||||
|
>>> credit.execute('credit')
|
||||||
|
>>> credit_note, = Invoice.find([('type', '=', 'in_credit_note')])
|
||||||
|
>>> credit_note.state
|
||||||
|
u'draft'
|
||||||
|
>>> credit_note.untaxed_amount == invoice.untaxed_amount
|
||||||
|
True
|
||||||
|
>>> credit_note.tax_amount == invoice.tax_amount
|
||||||
|
True
|
||||||
|
>>> credit_note.total_amount == invoice.total_amount
|
||||||
|
True
|
|
@ -10,7 +10,7 @@ if os.path.isdir(DIR):
|
||||||
sys.path.insert(0, os.path.dirname(DIR))
|
sys.path.insert(0, os.path.dirname(DIR))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
#import doctest TODO: Remove if no sceneario needed.
|
import doctest
|
||||||
import trytond.tests.test_tryton
|
import trytond.tests.test_tryton
|
||||||
from trytond.tests.test_tryton import test_view, test_depends
|
from trytond.tests.test_tryton import test_view, test_depends
|
||||||
from trytond.backend.sqlite.database import Database as SQLiteDatabase
|
from trytond.backend.sqlite.database import Database as SQLiteDatabase
|
||||||
|
@ -50,10 +50,9 @@ def doctest_dropdb(test):
|
||||||
def suite():
|
def suite():
|
||||||
suite = trytond.tests.test_tryton.suite()
|
suite = trytond.tests.test_tryton.suite()
|
||||||
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
|
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
|
||||||
# TODO: remove if no scenario needed.
|
suite.addTests(doctest.DocFileSuite('account_invoice_information_uom.rst',
|
||||||
#suite.addTests(doctest.DocFileSuite('scenario_invoice.rst',
|
setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
|
||||||
# setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
|
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
||||||
# optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
|
|
||||||
return suite
|
return suite
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -4,3 +4,4 @@ depends:
|
||||||
account_invoice
|
account_invoice
|
||||||
xml:
|
xml:
|
||||||
template.xml
|
template.xml
|
||||||
|
invoice.xml
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?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. -->
|
||||||
|
<data>
|
||||||
|
<xpath expr="/form/notebook/page[@id='general']/field[@name='taxes']" position="before">
|
||||||
|
<label name="info_unit"/>
|
||||||
|
<field name="info_unit"/>
|
||||||
|
<label name="info_quantity"/>
|
||||||
|
<field name="info_quantity"/>
|
||||||
|
<label name="info_unit_price"/>
|
||||||
|
<field name="info_unit_price"/>
|
||||||
|
<label name="info_amount"/>
|
||||||
|
<field name="info_amount"/>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?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. -->
|
||||||
|
<data>
|
||||||
|
<xpath expr="/tree/field[@name='amount']" position="after">
|
||||||
|
<field name="info_unit"/>
|
||||||
|
<field name="info_quantity"/>
|
||||||
|
<field name="info_unit_price"/>
|
||||||
|
<field name="info_amount"/>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
|
@ -4,12 +4,13 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<data>
|
<data>
|
||||||
<xpath expr="/form/notebook/page[@id='general']" position="after">
|
<xpath expr="/form/notebook/page[@id='general']" position="after">
|
||||||
<page id="information_uom" string="Information UOM">
|
<page id="information_uom" string="Information UOM">
|
||||||
<label name="use_info_uom"/>
|
<label name="use_info_unit"/>
|
||||||
<field name="use_info_uom"/>
|
<field name="use_info_unit"/>
|
||||||
|
<newline/>
|
||||||
<label name="info_ratio"/>
|
<label name="info_ratio"/>
|
||||||
<field name="info_ratio"/>
|
<field name="info_ratio"/>
|
||||||
<label name="info_uom"/>
|
<label name="info_unit"/>
|
||||||
<field name="info_uom"/>
|
<field name="info_unit"/>
|
||||||
<label name="info_list_price"/>
|
<label name="info_list_price"/>
|
||||||
<field name="info_list_price"/>
|
<field name="info_list_price"/>
|
||||||
<label name="info_cost_price"/>
|
<label name="info_cost_price"/>
|
||||||
|
|
Loading…
Reference in New Issue