diff --git a/modules/purchase_trade/cron.py b/modules/purchase_trade/cron.py
index f9b2fe8..6b4f022 100755
--- a/modules/purchase_trade/cron.py
+++ b/modules/purchase_trade/cron.py
@@ -12,9 +12,12 @@ class Cron(metaclass=PoolMeta):
@classmethod
def __setup__(cls):
- super().__setup__()
- cls.method.selection.append(
- ('forex.cron|update_forex', "Update Forex Prices"))
+ super().__setup__()
+ cls.method.selection.append(
+ ('forex.cron|update_forex', "Update Forex Prices"))
+ cls.method.selection.append(
+ ('valuation.valuation|update_daily_snapshot',
+ "Update Valuation Snapshot"))
class PriceCron(ModelSQL, ModelView):
"Price Cron"
diff --git a/modules/purchase_trade/cron.xml b/modules/purchase_trade/cron.xml
index 48d7ffb..32aff6c 100755
--- a/modules/purchase_trade/cron.xml
+++ b/modules/purchase_trade/cron.xml
@@ -36,10 +36,16 @@
-->
-
- forex.cron|update_forex
-
- days
-
-
-
+
+ forex.cron|update_forex
+
+ days
+
+
+
+ valuation.valuation|update_daily_snapshot
+
+ days
+
+
+
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index 8de7bdd..78225f7 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -722,6 +722,38 @@ class PurchaseTradeTestCase(ModuleTestCase):
{'type': 'derivative'},
])
+ def test_update_daily_snapshot_generates_all_purchases_and_unmatched_sales(self):
+ 'daily valuation cron snapshots purchases and unmatched sale lines'
+ Valuation = Pool().get('valuation.valuation')
+ PurchaseLine = Mock()
+ SaleLine = Mock()
+ purchase_lines = [Mock(id=1), Mock(id=2)]
+ unmatched_sale_line = Mock(id=3)
+ unmatched_sale_line.get_matched_lines.return_value = []
+ matched_sale_line = Mock(id=4)
+ matched_sale_line.get_matched_lines.return_value = [
+ Mock(lot_p=Mock(line=Mock(id=5)))]
+ PurchaseLine.search.return_value = purchase_lines
+ SaleLine.search.return_value = [unmatched_sale_line, matched_sale_line]
+
+ with patch(
+ 'trytond.modules.purchase_trade.valuation.Pool'
+ ) as PoolMock, patch.object(
+ Valuation, 'generate') as generate, patch.object(
+ Valuation, 'generate_from_sale_line'
+ ) as generate_from_sale_line:
+ PoolMock.return_value.get.side_effect = lambda name: {
+ 'purchase.line': PurchaseLine,
+ 'sale.line': SaleLine,
+ }[name]
+
+ Valuation.update_daily_snapshot()
+
+ generate.assert_any_call(purchase_lines[0])
+ generate.assert_any_call(purchase_lines[1])
+ self.assertEqual(generate.call_count, 2)
+ generate_from_sale_line.assert_called_once_with(unmatched_sale_line)
+
def test_create_pnl_fee_from_line_accepts_missing_rate_amount(self):
'purchase fee valuation treats an uncomputed rate amount as zero'
Valuation = Pool().get('valuation.valuation')
diff --git a/modules/purchase_trade/valuation.py b/modules/purchase_trade/valuation.py
index 2e31631..23304cd 100644
--- a/modules/purchase_trade/valuation.py
+++ b/modules/purchase_trade/valuation.py
@@ -1225,6 +1225,29 @@ class Valuation(ValuationBase, ModelView):
"Valuation"
__name__ = 'valuation.valuation'
+ @classmethod
+ def update_daily_snapshot(cls):
+ PurchaseLine = Pool().get('purchase.line')
+ SaleLine = Pool().get('sale.line')
+
+ purchase_lines = PurchaseLine.search([])
+ sale_lines = [
+ sale_line for sale_line in SaleLine.search([])
+ if cls._sale_line_is_unmatched(sale_line)
+ ]
+
+ for line in purchase_lines:
+ cls.generate(line)
+
+ for sale_line in sale_lines:
+ cls.generate_from_sale_line(sale_line)
+
+ logger.info(
+ "Updated valuation snapshot for %s purchase line(s) and "
+ "%s unmatched sale line(s)",
+ len(purchase_lines),
+ len(sale_lines))
+
@classmethod
def get_totals(cls):
cursor = Transaction().connection.cursor()