changeset 867d5edb5f75 in modules/sale:default
details: https://hg.tryton.org/modules/sale?cmd=changeset&node=867d5edb5f75
description:
        Add POS to sale reporting

        issue11299
        review397491002
diffstat:

 sale_reporting.py |  152 ++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 97 insertions(+), 55 deletions(-)

diffs (346 lines):

diff -r c64ccc6f426b -r 867d5edb5f75 sale_reporting.py
--- a/sale_reporting.py Wed Mar 09 00:57:17 2022 +0100
+++ b/sale_reporting.py Sat Mar 26 12:19:12 2022 +0100
@@ -8,10 +8,11 @@
 except ImportError:
     pygal = None
 from dateutil.relativedelta import relativedelta
-from sql import Column, Literal, Null, With
+from sql import Column, Literal, Null, Union, With
 from sql.aggregate import Count, Max, Min, Sum
 from sql.conditionals import Coalesce
 from sql.functions import Ceil, CurrentTimestamp, DateTrunc, Log, Power
+from sql.operators import Concat
 
 from trytond.i18n import lazy_gettext
 from trytond.model import ModelSQL, ModelView, UnionMixin, fields
@@ -57,17 +58,49 @@
             with_=withs.values())
 
     @classmethod
+    def _sale_line(cls, length, index, company_id=None):
+        pool = Pool()
+        Line = pool.get('sale.line')
+        Sale = pool.get('sale.sale')
+
+        line = Line.__table__()
+        sale = Sale.__table__()
+
+        return (line
+            .join(sale, condition=line.sale == sale.id)
+            .select(
+                (line.id * length + index).as_('id'),
+                line.product.as_('product'),
+                Coalesce(line.actual_quantity, line.quantity).as_('quantity'),
+                line.unit_price.as_('unit_price'),
+                Concat('sale.sale,', line.sale).as_('order'),
+                sale.sale_date.as_('date'),
+                sale.company.as_('company'),
+                sale.currency.as_('currency'),
+                sale.party.as_('customer'),
+                sale.warehouse.as_('location'),
+                sale.shipment_address.as_('shipment_address'),
+                where=sale.state.in_(cls._sale_states())
+                & (sale.company == company_id),
+                ))
+
+    @classmethod
+    def _lines(cls):
+        return [cls._sale_line]
+
+    @classmethod
     def _joins(cls):
         pool = Pool()
         Company = pool.get('company.company')
         Currency = pool.get('currency.currency')
-        Line = pool.get('sale.line')
-        Sale = pool.get('sale.sale')
+        context = Transaction().context
 
         tables = {}
-        tables['line'] = line = Line.__table__()
-        tables['line.sale'] = sale = Sale.__table__()
-        tables['line.sale.company'] = company = Company.__table__()
+        company = context.get('company')
+        lines = cls._lines()
+        tables['line'] = line = Union(*(
+                l(len(lines), i, company) for i, l in enumerate(lines)))
+        tables['line.company'] = company = Company.__table__()
         withs = {}
         currency_sale = With(query=Currency.currency_rate_sql())
         withs['currency_sale'] = currency_sale
@@ -75,32 +108,29 @@
         withs['currency_company'] = currency_company
 
         from_item = (line
-            .join(sale, condition=line.sale == sale.id)
             .join(currency_sale,
-                condition=(sale.currency == currency_sale.currency)
-                & (currency_sale.start_date <= sale.sale_date)
+                condition=(line.currency == currency_sale.currency)
+                & (currency_sale.start_date <= line.date)
                 & ((currency_sale.end_date == Null)
-                    | (currency_sale.end_date >= sale.sale_date))
+                    | (currency_sale.end_date >= line.date))
                 )
-            .join(company, condition=sale.company == company.id)
+            .join(company, condition=line.company == company.id)
             .join(currency_company,
                 condition=(company.currency == currency_company.currency)
-                & (currency_company.start_date <= sale.sale_date)
+                & (currency_company.start_date <= line.date)
                 & ((currency_company.end_date == Null)
-                    | (currency_company.end_date >= sale.sale_date))
+                    | (currency_company.end_date >= line.date))
                 ))
         return from_item, tables, withs
 
     @classmethod
     def _columns(cls, tables, withs):
         line = tables['line']
-        sale = tables['line.sale']
         currency_company = withs['currency_company']
         currency_sale = withs['currency_sale']
 
-        quantity = Coalesce(line.actual_quantity, line.quantity)
         revenue = cls.revenue.sql_cast(
-            Sum(quantity * line.unit_price
+            Sum(line.quantity * line.unit_price
                 * currency_company.rate / currency_sale.rate))
         return [
             cls._column_id(tables, withs).as_('id'),
@@ -108,9 +138,9 @@
             CurrentTimestamp().as_('create_date'),
             cls.write_uid.sql_cast(Literal(Null)).as_('write_uid'),
             cls.write_date.sql_cast(Literal(Null)).as_('write_date'),
-            sale.company.as_('company'),
+            line.company.as_('company'),
             revenue.as_('revenue'),
-            Count(sale.id, distinct=True).as_('number'),
+            Count(line.order, distinct=True).as_('number'),
             ]
 
     @classmethod
@@ -120,25 +150,30 @@
 
     @classmethod
     def _group_by(cls, tables, withs):
-        sale = tables['line.sale']
-        return [sale.company]
+        line = tables['line']
+        return [line.company]
 
     @classmethod
     def _where(cls, tables, withs):
+        pool = Pool()
+        Location = pool.get('stock.location')
         context = Transaction().context
-        sale = tables['line.sale']
+        line = tables['line']
 
-        where = sale.company == context.get('company')
-        where &= sale.state.in_(cls._sale_states())
+        where = Literal(True)
         from_date = context.get('from_date')
         if from_date:
-            where &= sale.sale_date >= from_date
+            where &= line.date >= from_date
         to_date = context.get('to_date')
         if to_date:
-            where &= sale.sale_date <= to_date
+            where &= line.date <= to_date
         warehouse = context.get('warehouse')
         if warehouse:
-            where &= sale.warehouse == warehouse
+            locations = Location.search([
+                    ('parent', 'child_of', warehouse),
+                    ],
+                query=True)
+            where &= line.location.in_(locations)
         return where
 
     @classmethod
@@ -194,8 +229,8 @@
     @classmethod
     def _column_date(cls, tables, withs):
         context = Transaction().context
-        sale = tables['line.sale']
-        date = DateTrunc(context.get('period'), sale.sale_date)
+        line = tables['line']
+        date = DateTrunc(context.get('period'), line.date)
         date = cls.date.sql_cast(date)
         return date
 
@@ -299,15 +334,15 @@
 
     @classmethod
     def _columns(cls, tables, withs):
-        sale = tables['line.sale']
+        line = tables['line']
         return super(CustomerMixin, cls)._columns(tables, withs) + [
-            sale.party.as_('customer')]
+            line.customer.as_('customer')]
 
     @classmethod
     def _group_by(cls, tables, withs):
-        sale = tables['line.sale']
+        line = tables['line']
         return super(CustomerMixin, cls)._group_by(tables, withs) + [
-            sale.party]
+            line.customer]
 
     def get_rec_name(self, name):
         return self.customer.rec_name
@@ -327,8 +362,15 @@
 
     @classmethod
     def _column_id(cls, tables, withs):
-        sale = tables['line.sale']
-        return sale.party
+        line = tables['line']
+        return line.customer
+
+    @classmethod
+    def _where(cls, tables, withs):
+        line = tables['line']
+        where = super()._where(tables, withs)
+        where &= line.customer != Null
+        return where
 
 
 class CustomerTimeseries(CustomerMixin, AbstractTimeseries, ModelView):
@@ -345,18 +387,18 @@
         pool = Pool()
         PartyCategory = pool.get('party.party-party.category')
         from_item, tables, withs = super()._joins()
-        if 'line.sale.party.party_category' not in tables:
+        if 'line.customer.party_category' not in tables:
             party_category = PartyCategory.__table__()
-            tables['line.sale.party.party_category'] = party_category
-            sale = tables['line.sale']
+            tables['line.customer.party_category'] = party_category
+            line = tables['line']
             from_item = (from_item
                 .join(party_category,
-                    condition=sale.party == party_category.party))
+                    condition=line.customer == party_category.party))
         return from_item, tables, withs
 
     @classmethod
     def _columns(cls, tables, withs):
-        party_category = tables['line.sale.party.party_category']
+        party_category = tables['line.customer.party_category']
         return super()._columns(tables, withs) + [
             party_category.category.as_('category')]
 
@@ -366,7 +408,7 @@
         Category = pool.get('party.category')
         category = Category.__table__()
         line = tables['line']
-        party_category = tables['line.sale.party.party_category']
+        party_category = tables['line.customer.party_category']
         # Get a stable number of categories over time
         # by using a number one order bigger.
         nb_category = category.select(
@@ -375,12 +417,12 @@
 
     @classmethod
     def _group_by(cls, tables, withs):
-        party_category = tables['line.sale.party.party_category']
+        party_category = tables['line.customer.party_category']
         return super()._group_by(tables, withs) + [party_category.category]
 
     @classmethod
     def _where(cls, tables, withs):
-        party_category = tables['line.sale.party.party_category']
+        party_category = tables['line.customer.party_category']
         where = super()._where(tables, withs)
         where &= party_category.category != Null
         return where
@@ -404,7 +446,7 @@
 
     @classmethod
     def _column_id(cls, tables, withs):
-        party_category = tables['line.sale.party.party_category']
+        party_category = tables['line.customer.party_category']
         return party_category.category
 
 
@@ -795,29 +837,29 @@
         pool = Pool()
         Address = pool.get('party.address')
         from_item, tables, withs = super(CountryMixin, cls)._joins()
-        if 'line.sale.shipment_address' not in tables:
+        if 'line.shipment_address' not in tables:
             address = Address.__table__()
-            tables['line.sale.shipment_address'] = address
-            sale = tables['line.sale']
+            tables['line.shipment_address'] = address
+            line = tables['line']
             from_item = (from_item
-                .join(address, condition=sale.shipment_address == address.id))
+                .join(address, condition=line.shipment_address == address.id))
         return from_item, tables, withs
 
     @classmethod
     def _columns(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return super(CountryMixin, cls)._columns(tables, withs) + [
             address.country.as_('country')]
 
     @classmethod
     def _group_by(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return super(CountryMixin, cls)._group_by(tables, withs) + [
             address.country]
 
     @classmethod
     def _where(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         where = super(CountryMixin, cls)._where(tables, withs)
         where &= address.country != Null
         return where
@@ -837,7 +879,7 @@
 
     @classmethod
     def _column_id(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return address.country
 
     def get_rec_name(self, name):
@@ -855,19 +897,19 @@
 
     @classmethod
     def _columns(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return super(SubdivisionMixin, cls)._columns(tables, withs) + [
             address.subdivision.as_('subdivision')]
 
     @classmethod
     def _group_by(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return super(SubdivisionMixin, cls)._group_by(tables, withs) + [
             address.subdivision]
 
     @classmethod
     def _where(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         where = super(SubdivisionMixin, cls)._where(tables, withs)
         where &= address.subdivision != Null
         return where
@@ -888,7 +930,7 @@
 
     @classmethod
     def _column_id(cls, tables, withs):
-        address = tables['line.sale.shipment_address']
+        address = tables['line.shipment_address']
         return address.subdivision
 
     def get_rec_name(self, name):

Reply via email to