diff --git a/line.py b/line.py
index 9fd6c9c..3ae1c5b 100644
--- a/line.py
+++ b/line.py
@@ -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])
diff --git a/locale/de.po b/locale/de.po
index caeda7a..c7567ee 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -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 #
diff --git a/locale/en.po b/locale/en.po
index b1f4b77..5b835d4 100644
--- a/locale/en.po
+++ b/locale/en.po
@@ -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"
diff --git a/message.xml b/message.xml
index 8dea6b1..5c4ead6 100644
--- a/message.xml
+++ b/message.xml
@@ -14,6 +14,9 @@ full copyright notices and license terms. -->
Quantity and Amount must with same sign for line %(linetxt)s.
+
+ Cannot transfer quantities between cashbooks with different unit-categories (%(cat1)s != %(cat2)s).
+
diff --git a/mixin.py b/mixin.py
index 14d7f0c..078c714 100644
--- a/mixin.py
+++ b/mixin.py
@@ -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):
diff --git a/tests/test_book.py b/tests/test_book.py
index 990195b..1ecb8d2 100644
--- a/tests/test_book.py
+++ b/tests/test_book.py
@@ -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],
- {
- 'lines': [('create', [{
- 'date': date(2022, 5, 1),
- 'description': 'Transfer',
- 'category': category_out.id,
- 'bookingtype': 'mvout',
- 'booktransf': book2.id,
- 'amount': Decimal('1.0'),
- '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))
+ 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 In',
+ 'category': category_out.id,
+ 'bookingtype': 'mvin',
+ 'amount': Decimal('1.0'),
+ 'booktransf': book2.id,
+ 'quantity': Decimal('1.5'),
+ }])],
+ },
+ ])
# end CbInvTestCase
diff --git a/view/line_form.xml b/view/line_form.xml
index 51855ad..35e5369 100644
--- a/view/line_form.xml
+++ b/view/line_form.xml
@@ -15,4 +15,12 @@ full copyright notices and license terms. -->
+
+
+
+
+
+
+
+