line/mixin: umrechnung anzahl + tests

This commit is contained in:
Frederik Jaeckel 2023-01-15 00:36:02 +01:00
parent 7990608943
commit 8acfa35289
7 changed files with 695 additions and 74 deletions

78
line.py
View file

@ -13,21 +13,14 @@ from trytond.modules.cashbook.line import STATES, DEPENDS
from .mixin import SecondUomMixin
STATESQ = {
'required': Or(
Eval('feature', '') == 'asset',
Eval('booktransf_feature', '') == 'asset',
),
'invisible': ~Or(
Eval('feature', '') == 'asset',
Eval('booktransf_feature', '') == 'asset',
),
'required': Eval('feature', '') == 'asset',
'invisible': Eval('feature', '') != 'asset',
'readonly': Or(
STATES['readonly'],
Eval('bookingtype', '').in_(['spin', 'spout']),
),
}
DEPENDSQ = DEPENDS+['feature', 'booktransf_feature',
'quantity_digits', 'bookingtype']
DEPENDSQ = DEPENDS+['feature', 'quantity_digits', 'bookingtype']
class Line(SecondUomMixin, metaclass=PoolMeta):
@ -71,10 +64,19 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
'on_change_with_quantity_balance')
@classmethod
def get_debit_credit(cls, values):
def get_debit_credit(cls, values, line=None):
""" compute quantity_debit/quantity_credit from quantity
"""
values2 = super(Line, cls).get_debit_credit(values)
Cashbook = Pool().get('cashbook.book')
result = super(Line, cls).get_debit_credit(values, line)
if line:
cashbook = line.cashbook
else:
id_cashbook = values.get('cashbook', None)
cashbook = None
if id_cashbook:
cashbook = Cashbook.browse([id_cashbook])[0]
if isinstance(values, dict):
type_ = values.get('bookingtype', None)
@ -83,28 +85,53 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
type_ = getattr(values, 'bookingtype', None)
quantity = getattr(values, 'quantity', None)
if type_:
if (type_ is not None) and (cashbook.feature == 'asset'):
if quantity is not None:
if type_ in ['in', 'mvin', 'spin']:
values2.update({
result.update({
'quantity_debit': Decimal('0.0'),
'quantity_credit': quantity,
})
elif type_ in ['out', 'mvout', 'spout']:
values2.update({
result.update({
'quantity_debit': quantity,
'quantity_credit': Decimal('0.0'),
})
else :
raise ValueError('invalid "bookingtype"')
return values2
return result
@classmethod
def get_counterpart_values(cls, line, values={}):
""" add quantity to counterpart
"""
result = super(Line, cls).get_counterpart_values(line, values)
result['quantity'] = line.quantity
line_uom = getattr(line.quantity_uom, 'id', None)
booktransf_uom = getattr(getattr(line.booktransf, 'quantity_uom', {}), 'id', None)
if booktransf_uom is None:
# counterpart-cashbook has no uom -> no quantity
result.update({
'quantity': None,
'quantity_2nd_uom': None,
})
else :
if line_uom is None:
result.update({
'quantity': line.quantity,
'quantity_2nd_uom': None,
})
elif line_uom == booktransf_uom:
result.update({
'quantity': line.quantity,
'quantity_2nd_uom': None,
})
else :
result.update({
'quantity': line.quantity_2nd_uom,
'quantity_2nd_uom': line.quantity,
})
return result
@fields.depends('id', 'date', 'cashbook', \
@ -132,7 +159,7 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
if self.quantity != Decimal('0.0'):
return (
self.amount / self.quantity
).quantize(Decimal(str(1/10**digit)))
).quantize(Decimal(Decimal(1) / 10**digit))
@fields.depends('cashbook', '_parent_cashbook.quantity_uom')
def on_change_with_quantity_uom(self, name=None):
@ -179,6 +206,19 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
linetxt = line.rec_name,
))
@classmethod
def add_2nd_unit_values(cls, values):
""" extend create-values
"""
Cashbook = Pool().get('cashbook.book')
values = super(Line, cls).add_2nd_unit_values(values)
cashbook = values.get('cashbook', None)
if cashbook:
values.update(cls.add_2nd_quantity(values, Cashbook(cashbook).quantity_uom))
return values
@classmethod
def write(cls, *args):
""" add or update quanity_debit/credit
@ -193,7 +233,7 @@ class Line(SecondUomMixin, metaclass=PoolMeta):
values2.update(values)
values2.update(cls.get_debit_credit({
x:values.get(x, getattr(line, x)) for x in ['quantity', 'bookingtype']
}))
}, line=line))
to_write.extend([lines, values2])
else :
to_write.extend([lines, values])

View file

@ -18,6 +18,10 @@ msgctxt "model:ir.message,text:msg_line_sign_mismatch"
msgid "Quantity and Amount must with same sign for line %(linetxt)s."
msgstr "Menge und Betrag müssen für Zeile %(linetxt)s mit demselben Vorzeichen versehen werden."
msgctxt "model:ir.message,text:msg_uomcat_mismatch"
msgid "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)."
msgstr "Es können keine Mengen zwischen Kassenbüchern mit verschiedenen Einheitenkategorien (%(cat1)s != %(cat2)s) übertragen werden."
#################
# cashbook.book #

View file

@ -14,6 +14,10 @@ msgctxt "model:ir.message,text:msg_line_sign_mismatch"
msgid "Quantity and Amount must with same sign for line %(linetxt)s."
msgstr "Quantity and Amount must with same sign for line %(linetxt)s."
msgctxt "model:ir.message,text:msg_uomcat_mismatch"
msgid "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)."
msgstr "Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s)."
msgctxt "view:cashbook.book:"
msgid "Asset"
msgstr "Asset"
@ -142,6 +146,26 @@ msgctxt "help:cashbook.line,quantity_balance:"
msgid "Number of shares in the cashbook up to the current row if the default sort applies."
msgstr "Number of shares in the cashbook up to the current row if the default sort applies."
msgctxt "field:cashbook.line,quantity_2nd_uom:"
msgid "Quantity Second UOM"
msgstr "Quantity Second UOM"
msgctxt "field:cashbook.line,quantity2nd:"
msgid "2nd UOM"
msgstr "2nd UOM"
msgctxt "field:cashbook.line,quantity2nd_digits:"
msgid "2nd UOM Digits"
msgstr "2nd UOM Digits"
msgctxt "field:cashbook.line,factor_2nd_uom:"
msgid "Conversion factor"
msgstr "Conversion factor"
msgctxt "help:cashbook.line,factor_2nd_uom:"
msgid "Conversion factor between the units of the participating cash books."
msgstr "Conversion factor between the units of the participating cash books."
msgctxt "field:cashbook.recon,start_quantity:"
msgid "Start Quantity"
msgstr "Start Quantity"

View file

@ -14,6 +14,9 @@ full copyright notices and license terms. -->
<record model="ir.message" id="msg_line_sign_mismatch">
<field name="text">Quantity and Amount must with same sign for line %(linetxt)s.</field>
</record>
<record model="ir.message" id="msg_uomcat_mismatch">
<field name="text">Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s).</field>
</record>
</data>
</tryton>

141
mixin.py
View file

@ -7,6 +7,8 @@ from trytond.model import fields
from trytond.pyson import Eval, Bool, Or
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.i18n import gettext
from trytond.modules.product.uom import uom_conversion_digits
from trytond.modules.cashbook.mixin import STATES, DEPENDS
from decimal import Decimal
@ -41,24 +43,147 @@ class SecondUomMixin(object):
'required': Bool(Eval('quantity2nd')),
'invisible': ~Bool(Eval('quantity2nd')),
}, depends=DEPENDSQ+['quantity2nd_digits', 'quantity2nd']),
'on_change_with_rate_2nd_uom', setter='set_rate_2nd_uom')
'on_change_with_factor_2nd_uom', setter='set_factor_2nd_uom')
quantity2nd = fields.Function(fields.Many2One(model_name='product.uom',
string="2nd UOM", readonly=True), 'on_change_with_quantity2nd')
quantity2nd_digits = fields.Function(fields.Integer(string='2nd UOM Digits',
readonly=True), 'on_change_with_quantity2nd_digits')
@fields.depends('quantity', 'quantity_2nd_oum')
def quantize_quantity(self, value):
""" quantize for line-quantity
"""
return Decimal(value).quantize(Decimal(Decimal(1) / 10 ** self.quantity_digits))
@classmethod
def add_2nd_quantity(cls, values, from_uom):
""" add second uom quantity if missing
"""
pool = Pool()
UOM = pool.get('product.uom')
Cashbook = pool.get('cashbook.book')
booktransf = values.get('booktransf', None)
quantity = values.get('quantity', None)
quantity_2nd_uom = values.get('quantity_2nd_uom', None)
if (quantity is not None) and (booktransf is not None) and \
(from_uom is not None):
if quantity_2nd_uom is None:
booktransf = Cashbook(booktransf)
if booktransf.quantity_uom:
if from_uom.id != booktransf.quantity_uom.id:
# deny impossible transfer
if from_uom.category.id != booktransf.quantity_uom.category.id:
raise UserError(gettext(
'cashbook_investment.msg_uomcat_mismatch',
cat1 = from_uom.category.rec_name,
cat2 = booktransf.quantity_uom.category.rec_name,
))
values['quantity_2nd_uom'] = Decimal(UOM.compute_qty(
from_uom,
float(quantity),
booktransf.quantity_uom,
round=False,
)).quantize(Decimal(
Decimal(1) / 10 ** booktransf.quantity_digits)
)
return values
@classmethod
def set_factor_2nd_uom(cls, lines, name, value):
""" compute quantity_2nd_uom, write to db
"""
Line2 = Pool().get(cls.__name__)
to_write = []
if name != 'factor_2nd_uom':
return
for line in lines:
if line.booktransf is None:
continue
if line.cashbook.quantity_uom.id == line.booktransf.quantity_uom.id:
continue
to_write.extend([
[line],
{
'quantity_2nd_uom': line.quantize_quantity(
line.booktransf.quantity_uom.round(
float(line.quantity * value))
),
}])
if len(to_write) > 0:
Line2.write(*to_write)
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \
'quantity_uom', 'quantity_digits', 'quantity', \
'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_booktransf(self):
""" update quantity_2nd_uom
"""
self.on_change_factor_2nd_uom()
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \
'quantity_uom', 'quantity_digits', 'quantity', \
'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_quantity(self):
""" update quantity_2nd_uom
"""
self.on_change_factor_2nd_uom()
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', \
'quantity_uom', 'quantity_digits', 'quantity', \
'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_factor_2nd_uom(self):
""" update quantity_2nd_uom + factor_2nd_uom
"""
UOM = Pool().get('product.uom')
if (self.quantity is None) or (self.booktransf is None):
self.quantity_2nd_uom = None
self.factor_2nd_uom = None
return
if (self.booktransf.quantity_uom is None) or \
(self.quantity_uom is None):
return
if self.factor_2nd_uom is None:
# no factor set, use factor of target-uom
self.quantity_2nd_uom = self.quantize_quantity(
UOM.compute_qty(
self.quantity_uom,
float(self.quantity),
self.booktransf.quantity_uom,
round=False,
))
if self.quantity != Decimal('0.0'):
self.factor_2nd_uom = (
self.quantity_2nd_uom / self.quantity
).quantize(Decimal(Decimal(1) / 10 ** uom_conversion_digits[1]))
else :
self.quantity_2nd_uom = self.quantize_quantity(
self.quantity * self.factor_2nd_uom)
@fields.depends('quantity', 'quantity_2nd_uom', 'factor_2nd_uom')
def on_change_quantity_2nd_uom(self):
""" update factor_2nd_uom by quantity
"""
self.factor_2nd_uom = self.on_change_with_factor_2nd_uom()
@fields.depends('quantity', 'quantity_2nd_uom')
def on_change_with_factor_2nd_uom(self, name=None):
""" get factor from uom
"""
Rate = Pool().get('currency.currency.rate')
if (self.quantity is not None) and \
(self.quantity_2nd_oum is not None):
if (self.quantity is not None) and (self.quantity_2nd_uom is not None):
if self.quantity != Decimal('0.0'):
exp = Decimal(Decimal(1) / 10 ** Rate.rate.digits[1])
return (self.quantity_2nd_oum / self.quantity).quantize(exp)
exp = Decimal(Decimal(1) / 10 ** uom_conversion_digits[1])
return (self.quantity_2nd_uom / self.quantity).quantize(exp)
@fields.depends('booktransf', '_parent_booktransf.quantity_uom', 'quantity_uom')
def on_change_with_quantity2nd(self, name=None):

View file

@ -597,8 +597,9 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
self.assertEqual(book.rec_name, 'Book 1 | -1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, None)
self.assertEqual(book.lines[0].quantity_debit, None)
self.assertEqual(book.lines[0].feature, 'gen')
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Asset-Book | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
@ -610,8 +611,8 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
'lines': [('write', [book.lines[0]], {'quantity': Decimal('2.5')})],
}])
self.assertEqual(book.lines[0].quantity, Decimal('2.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('2.5'))
self.assertEqual(book.lines[0].quantity_credit, None)
self.assertEqual(book.lines[0].quantity_debit, None)
# check counterpart
self.assertEqual(book.lines[0].booktransf.rec_name, 'Asset-Book | 0.00 usd | Open')
@ -621,33 +622,296 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(book.rec_name, 'Book 1 | -1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Asset-Book | 1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[0].bookingtype, 'mvout')
self.assertEqual(book.lines[0].feature, 'gen')
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('0.0'))
self.assertEqual(book.lines[0].debit, Decimal('1.0'))
self.assertEqual(book.lines[0].quantity, Decimal('2.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('2.5'))
self.assertEqual(book.lines[0].quantity_credit, None) # feature != asset
self.assertEqual(book.lines[0].quantity_debit, None) # --> no quantity-credit/debit
self.assertEqual(book.lines[0].quantity_2nd_uom, None)
self.assertEqual(book.lines[0].factor_2nd_uom, None)
self.assertEqual(book.lines[0].quantity2nd, None)
self.assertEqual(book.lines[0].quantity2nd_digits, 4)
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(book2.rec_name, 'Asset-Book | 1.00 usd | Open')
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer Out [Book 1 | -1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].quantity, Decimal('2.5'))
self.assertEqual(book2.lines[0].quantity_credit, Decimal('2.5'))
self.assertEqual(book2.lines[0].quantity_debit, Decimal('0.0'))
self.assertEqual(book2.lines[0].bookingtype, 'mvin')
self.assertEqual(book2.lines[0].feature, 'asset')
self.assertEqual(book2.lines[0].amount, Decimal('1.0'))
self.assertEqual(book2.lines[0].credit, Decimal('1.0'))
self.assertEqual(book2.lines[0].debit, Decimal('0.0'))
self.assertEqual(book2.lines[0].quantity, Decimal('2.5'))
self.assertEqual(book2.lines[0].quantity_credit, Decimal('2.5')) # feature=asset
self.assertEqual(book2.lines[0].quantity_debit, Decimal('0.0')) # needs quantity-credit/debit
self.assertEqual(book2.lines[0].quantity_2nd_uom, None)
self.assertEqual(book2.lines[0].factor_2nd_uom, None)
self.assertEqual(book2.lines[0].quantity2nd, None)
self.assertEqual(book2.lines[0].quantity2nd_digits, 4)
self.assertEqual(book2.lines[0].asset_rate, Decimal('0.4'))
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|to|-1.00 usd|Transfer Out [Asset-Book | 1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
l1 = list(book.lines)
l1.append(Line(
bookingtype = 'mvout',
amount = Decimal('2.5'),
quantity = Decimal('2.5'),
booktransf = book2,
))
book.lines = l1
book.lines[-1].on_change_quantity()
@with_transaction()
def test_assetbook_check_mvout_two_asset_accounts_invalid_category(self):
""" create cashbook + line, bookingtype 'mvout'
transfer from asset-book to asset-book, check deny of
invalid uom-catgories
def test_assetbook_check_mvin(self):
""" create cashbook + line, bookingtype 'mvin'
transfer from depot to cash (sell asset, transfer to cash)
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Category = pool.get('cashbook.category')
BType = pool.get('cashbook.type')
type_cash = self.prep_type()
type_depot = self.prep_type('Depot', 'D')
BType.write(*[
[type_depot],
{
'feature': 'asset',
}])
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
asset = self.prep_asset_item(
company=company,
product = self.prep_asset_product(name='Product 1'))
self.assertEqual(asset.symbol, 'usd/u')
book2, = Book.create([{
'name': 'Asset-Book',
'btype': type_depot.id,
'asset': asset.id,
'quantity_uom': asset.uom.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
}])
book, = Book.create([{
'name': 'Book 1',
'btype': type_cash.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer In',
'category': category_out.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
'quantity': Decimal('1.5'),
}])],
}])
self.assertEqual(book.rec_name, 'Book 1 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, None)
self.assertEqual(book.lines[0].quantity_debit, None)
self.assertEqual(book.lines[0].feature, 'gen')
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
# check counterpart
self.assertEqual(book.lines[0].booktransf.rec_name, 'Asset-Book | 0.00 usd | Open')
self.assertEqual(book.lines[0].booktransf.btype.feature, 'asset')
self.assertEqual(book.lines[0].booktransf_feature, 'asset')
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(book.rec_name, 'Book 1 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book | -1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[0].bookingtype, 'mvin')
self.assertEqual(book.lines[0].feature, 'gen')
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, None) # feature != asset
self.assertEqual(book.lines[0].quantity_debit, None) # --> no quantity-credit/debit
self.assertEqual(book.lines[0].quantity_2nd_uom, None)
self.assertEqual(book.lines[0].factor_2nd_uom, None)
self.assertEqual(book.lines[0].quantity2nd, None)
self.assertEqual(book.lines[0].quantity2nd_digits, 4)
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(book2.rec_name, 'Asset-Book | -1.00 usd | Open')
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer In [Book 1 | 1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].bookingtype, 'mvout')
self.assertEqual(book2.lines[0].feature, 'asset')
self.assertEqual(book2.lines[0].amount, Decimal('1.0'))
self.assertEqual(book2.lines[0].credit, Decimal('0.0'))
self.assertEqual(book2.lines[0].debit, Decimal('1.0'))
self.assertEqual(book2.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book2.lines[0].quantity_credit, Decimal('0.0')) # feature=asset
self.assertEqual(book2.lines[0].quantity_debit, Decimal('1.5')) # needs quantity-credit/debit
self.assertEqual(book2.lines[0].quantity_2nd_uom, None)
self.assertEqual(book2.lines[0].factor_2nd_uom, None)
self.assertEqual(book2.lines[0].quantity2nd, None)
self.assertEqual(book2.lines[0].quantity2nd_digits, 4)
self.assertEqual(book2.lines[0].asset_rate, Decimal('0.6667'))
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book | -1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
@with_transaction()
def test_assetbook_check_mvin_two_assetbooks(self):
""" create cashbook + line, bookingtype 'mvin'
transfer from depot to depot, equal uom on both cashbooks
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Category = pool.get('cashbook.category')
BType = pool.get('cashbook.type')
type_cash = self.prep_type()
type_depot = self.prep_type('Depot', 'D')
BType.write(*[
[type_depot],
{
'feature': 'asset',
}])
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
asset = self.prep_asset_item(
company=company,
product = self.prep_asset_product(name='Product 1'))
self.assertEqual(asset.symbol, 'usd/u')
book2, = Book.create([{
'name': 'Asset-Book 1',
'btype': type_depot.id,
'asset': asset.id,
'quantity_uom': asset.uom.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
}])
book, = Book.create([{
'name': 'Asset-Book 2',
'btype': type_depot.id,
'asset': asset.id,
'quantity_uom': asset.uom.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer In',
'category': category_out.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
'quantity': Decimal('1.5'),
}])],
}])
self.assertEqual(book.rec_name, 'Asset-Book 2 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('0.0'))
self.assertEqual(book.lines[0].feature, 'asset')
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
# check counterpart
self.assertEqual(book.lines[0].booktransf.rec_name, 'Asset-Book 1 | 0.00 usd | Open')
self.assertEqual(book.lines[0].booktransf.btype.feature, 'asset')
self.assertEqual(book.lines[0].booktransf_feature, 'asset')
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(book.rec_name, 'Asset-Book 2 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | -1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[0].bookingtype, 'mvin')
self.assertEqual(book.lines[0].feature, 'asset')
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_2nd_uom, None)
self.assertEqual(book.lines[0].factor_2nd_uom, None)
self.assertEqual(book.lines[0].quantity2nd, None)
self.assertEqual(book.lines[0].quantity2nd_digits, 4)
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(book2.rec_name, 'Asset-Book 1 | -1.00 usd | Open')
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer In [Asset-Book 2 | 1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].bookingtype, 'mvout')
self.assertEqual(book2.lines[0].feature, 'asset')
self.assertEqual(book2.lines[0].amount, Decimal('1.0'))
self.assertEqual(book2.lines[0].credit, Decimal('0.0'))
self.assertEqual(book2.lines[0].debit, Decimal('1.0'))
self.assertEqual(book2.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book2.lines[0].quantity_credit, Decimal('0.0'))
self.assertEqual(book2.lines[0].quantity_debit, Decimal('1.5'))
self.assertEqual(book2.lines[0].quantity_2nd_uom, None)
self.assertEqual(book2.lines[0].factor_2nd_uom, None)
self.assertEqual(book2.lines[0].quantity2nd, None)
self.assertEqual(book2.lines[0].quantity2nd_digits, 4)
self.assertEqual(book2.lines[0].asset_rate, Decimal('0.6667'))
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | -1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
@with_transaction()
def test_assetbook_check_mvin_two_assetbooks_diff_uom_equal_uomcat(self):
""" create cashbook + line, bookingtype 'mvin'
transfer from depot to depot,
different uom (equal uom-category) on both cashbooks
"""
pool = Pool()
Book = pool.get('cashbook.book')
@ -655,8 +919,8 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
Category = pool.get('cashbook.category')
BType = pool.get('cashbook.type')
UOM = pool.get('product.uom')
Asset = pool.get('investment.asset')
ProdTempl = pool.get('product.template')
Asset = pool.get('investment.asset')
type_cash = self.prep_type()
type_depot = self.prep_type('Depot', 'D')
@ -678,12 +942,173 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
company=company,
product = self.prep_asset_product(name='Product 2'))
uom_kg = UOM.search([('symbol', '=', 'kg')])[0]
uom_grams = UOM.search([('symbol', '=', 'g')])[0]
uom_ounce = UOM.search([('symbol', '=', 'oz')])[0]
ProdTempl.write(*[
[asset1.product.template],
{
'default_uom': uom_grams.id,
},
[asset2.product.template],
{
'default_uom': uom_ounce.id,
},
])
Asset.write(*[
[asset1],
{
'uom': uom_grams.id,
},
[asset2],
{
'uom': uom_ounce.id,
},
])
self.assertEqual(asset1.symbol, 'usd/g')
self.assertEqual(asset2.symbol, 'usd/oz')
book2, = Book.create([{
'name': 'Asset-Book 1',
'btype': type_depot.id,
'asset': asset1.id,
'quantity_uom': asset1.uom.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
}])
book, = Book.create([{
'name': 'Asset-Book 2',
'btype': type_depot.id,
'asset': asset2.id,
'quantity_uom': asset2.uom.id,
'company': company.id,
'currency': company.currency.id,
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer In',
'category': category_out.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
'quantity': Decimal('1.5'),
}])],
}])
self.assertEqual(book.rec_name, 'Asset-Book 2 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_uom.symbol, 'oz')
self.assertEqual(book.lines[0].quantity_uom.factor, 0.028349523125)
self.assertEqual(book.lines[0].quantity2nd.symbol, 'g')
self.assertEqual(book.lines[0].quantity2nd.factor, 0.001)
self.assertEqual(book.lines[0].quantity_2nd_uom, Decimal('42.5243')) # 1.5 oz --> g
self.assertEqual(book.lines[0].factor_2nd_uom, Decimal('28.349533333333'))
self.assertEqual(book.lines[0].quantity2nd_digits, 4)
self.assertEqual(book.lines[0].feature, 'asset')
self.assertEqual(len(book2.lines), 0)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | 0.00 usd | Open]')
self.assertEqual(len(book.lines[0].references), 0)
# check counterpart
self.assertEqual(book.lines[0].booktransf.rec_name, 'Asset-Book 1 | 0.00 usd | Open')
self.assertEqual(book.lines[0].booktransf.btype.feature, 'asset')
self.assertEqual(book.lines[0].booktransf_feature, 'asset')
# set line to 'checked', this creates the counterpart
Line.wfcheck(list(book.lines))
self.assertEqual(book.rec_name, 'Asset-Book 2 | 1.00 usd | Open')
self.assertEqual(len(book.lines), 1)
self.assertEqual(book.lines[0].rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | -1.00 usd | Open]')
self.assertEqual(book.lines[0].state, 'check')
self.assertEqual(book.lines[0].bookingtype, 'mvin')
self.assertEqual(book.lines[0].feature, 'asset')
self.assertEqual(book.lines[0].amount, Decimal('1.0'))
self.assertEqual(book.lines[0].credit, Decimal('1.0'))
self.assertEqual(book.lines[0].debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_credit, Decimal('1.5'))
self.assertEqual(book.lines[0].quantity_debit, Decimal('0.0'))
self.assertEqual(book.lines[0].quantity_2nd_uom, Decimal('42.5243'))
self.assertEqual(book.lines[0].factor_2nd_uom, Decimal('28.349533333333'))
self.assertEqual(book.lines[0].quantity2nd.symbol, 'g')
self.assertEqual(book.lines[0].quantity2nd.factor, 0.001)
self.assertEqual(book.lines[0].quantity2nd_digits, 4)
self.assertEqual(len(book.lines[0].references), 1)
self.assertEqual(book.lines[0].reference, None)
self.assertEqual(book.lines[0].references[0].id, book2.lines[0].id)
self.assertEqual(book2.rec_name, 'Asset-Book 1 | -1.00 usd | Open')
self.assertEqual(len(book2.lines), 1)
self.assertEqual(book2.lines[0].rec_name, '05/01/2022|to|-1.00 usd|Transfer In [Asset-Book 2 | 1.00 usd | Open]')
self.assertEqual(book2.lines[0].state, 'check')
self.assertEqual(book2.lines[0].bookingtype, 'mvout')
self.assertEqual(book2.lines[0].feature, 'asset')
self.assertEqual(book2.lines[0].amount, Decimal('1.0'))
self.assertEqual(book2.lines[0].credit, Decimal('0.0'))
self.assertEqual(book2.lines[0].debit, Decimal('1.0'))
self.assertEqual(book2.lines[0].quantity, Decimal('42.5243'))
self.assertEqual(book2.lines[0].quantity_credit, Decimal('0.0'))
self.assertEqual(book2.lines[0].quantity_debit, Decimal('42.5243'))
self.assertEqual(book2.lines[0].quantity_2nd_uom, Decimal('1.5'))
self.assertEqual(book2.lines[0].factor_2nd_uom, Decimal('0.035273949248'))
self.assertEqual(book2.lines[0].quantity2nd.symbol, 'oz')
self.assertEqual(book2.lines[0].quantity2nd.factor, 0.028349523125)
self.assertEqual(book2.lines[0].quantity2nd_digits, 4)
self.assertEqual(book2.lines[0].asset_rate, Decimal('0.0235'))
self.assertEqual(book2.lines[0].reference.rec_name, '05/01/2022|from|1.00 usd|Transfer In [Asset-Book 1 | -1.00 usd | Open]')
self.assertEqual(len(book2.lines[0].references), 0)
@with_transaction()
def test_assetbook_check_mvin_two_assetbooks_diff_uom_diff_uomcat(self):
""" create cashbook + line, bookingtype 'mvin'
transfer from depot to depot,
different uom (different uom-category) on both cashbooks
"""
pool = Pool()
Book = pool.get('cashbook.book')
Line = pool.get('cashbook.line')
Category = pool.get('cashbook.category')
BType = pool.get('cashbook.type')
UOM = pool.get('product.uom')
ProdTempl = pool.get('product.template')
Asset = pool.get('investment.asset')
type_cash = self.prep_type()
type_depot = self.prep_type('Depot', 'D')
BType.write(*[
[type_depot],
{
'feature': 'asset',
}])
category_in = self.prep_category(cattype='in')
category_out = self.prep_category(name='Out Category', cattype='out')
company = self.prep_company()
party = self.prep_party()
asset1 = self.prep_asset_item(
company=company,
product = self.prep_asset_product(name='Product 1'))
asset2 = self.prep_asset_item(
company=company,
product = self.prep_asset_product(name='Product 2'))
uom_grams = UOM.search([('symbol', '=', 'g')])[0]
uom_min = UOM.search([('symbol', '=', 'min')])[0]
ProdTempl.write(*[
[asset1.product.template],
{
'default_uom': uom_kg.id,
'default_uom': uom_grams.id,
},
[asset2.product.template],
{
@ -694,18 +1119,18 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
Asset.write(*[
[asset1],
{
'uom': uom_kg.id,
'uom': uom_grams.id,
},
[asset2],
{
'uom': uom_min.id,
},
])
self.assertEqual(asset1.symbol, 'usd/kg')
self.assertEqual(asset1.symbol, 'usd/g')
self.assertEqual(asset2.symbol, 'usd/min')
book1, = Book.create([{
'name': 'Asset-Book - kg',
book2, = Book.create([{
'name': 'Asset-Book 1',
'btype': type_depot.id,
'asset': asset1.id,
'quantity_uom': asset1.uom.id,
@ -715,8 +1140,8 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
'start_date': date(2022, 5, 1),
}])
book2, = Book.create([{
'name': 'Asset-Book - min',
book, = Book.create([{
'name': 'Asset-Book 2',
'btype': type_depot.id,
'asset': asset2.id,
'quantity_uom': asset2.uom.id,
@ -725,31 +1150,23 @@ class CbInvTestCase(CashbookTestCase, InvestmentTestCase):
'number_sequ': self.prep_sequence().id,
'start_date': date(2022, 5, 1),
}])
self.assertEqual(book1.rec_name, 'Asset-Book - kg | 0.00 usd | Open')
self.assertEqual(book2.rec_name, 'Asset-Book - min | 0.00 usd | Open')
self.assertEqual(len(book1.lines), 0)
self.assertEqual(len(book2.lines), 0)
Book.write(*[
[book1],
self.assertRaisesRegex(UserError,
r'Cannot transfer quantities between cashbooks with different unit-categories \(Time != Weight\).',
Book.write,
*[
[book],
{
'lines': [('create', [{
'date': date(2022, 5, 1),
'description': 'Transfer',
'description': 'Transfer In',
'category': category_out.id,
'bookingtype': 'mvout',
'booktransf': book2.id,
'bookingtype': 'mvin',
'amount': Decimal('1.0'),
'booktransf': book2.id,
'quantity': Decimal('1.5'),
'quantity_2nd_uom': Decimal('10.5'),
}])],
}])
self.assertEqual(len(book1.lines), 1)
self.assertEqual(book1.lines[0].quantity_uom.symbol, 'kg')
self.assertEqual(book1.lines[0].quantity2nd.symbol, 'min')
self.assertEqual(book1.lines[0].quantity_digits, 4)
self.assertEqual(book1.lines[0].quantity2nd_digits, 4)
Line.wfcheck(list(book1.lines))
},
])
# end CbInvTestCase

View file

@ -15,4 +15,12 @@ full copyright notices and license terms. -->
<newline/>
</xpath>
<xpath expr="/form/field[@name='rate_2nd_currency']" position="after">
<newline/>
<label name="quantity_2nd_uom"/>
<field name="quantity_2nd_uom" symbol="quantity2nd"/>
<label name="factor_2nd_uom"/>
<field name="factor_2nd_uom"/>
</xpath>
</data>