Odoo18-Base/addons/pos_sale/report/sale_report.py
2025-01-06 10:57:38 +07:00

170 lines
6.5 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class SaleReport(models.Model):
_inherit = "sale.report"
@api.model
def _get_done_states(self):
done_states = super()._get_done_states()
done_states.extend(['paid', 'invoiced', 'done'])
return done_states
state = fields.Selection(
selection_add=[
('paid', 'Paid'),
('invoiced', 'Invoiced'),
('done', 'Posted')
],
)
order_reference = fields.Reference(selection_add=[('pos.order', 'POS Order')])
def _select_pos(self):
select_ = f"""
-MIN(l.id) AS id,
l.product_id AS product_id,
NULL AS line_invoice_status,
t.uom_id AS product_uom,
SUM(l.qty) AS product_uom_qty,
SUM(l.qty_delivered) AS qty_delivered,
SUM(l.qty - l.qty_delivered) AS qty_to_deliver,
CASE WHEN pos.state = 'invoiced' THEN SUM(l.qty) ELSE 0 END AS qty_invoiced,
CASE WHEN pos.state != 'invoiced' THEN SUM(l.qty) ELSE 0 END AS qty_to_invoice,
AVG(l.price_unit)
/ MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('account_currency_table.rate')}
AS price_unit,
SUM(l.price_subtotal_incl)
/ MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('account_currency_table.rate')}
AS price_total,
SUM(l.price_subtotal)
/ MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('account_currency_table.rate')}
AS price_subtotal,
(CASE WHEN pos.state != 'invoiced' THEN SUM(l.price_subtotal) ELSE 0 END)
/ MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('account_currency_table.rate')}
AS amount_to_invoice,
(CASE WHEN pos.state = 'invoiced' THEN SUM(l.price_subtotal) ELSE 0 END)
/ MIN({self._case_value_or_one('pos.currency_rate')})
* {self._case_value_or_one('account_currency_table.rate')}
AS amount_invoiced,
count(*) AS nbr,
pos.name AS name,
pos.date_order AS date,
(CASE WHEN pos.state = 'done' THEN 'sale' ELSE pos.state END) AS state,
NULL as invoice_status,
pos.partner_id AS partner_id,
pos.user_id AS user_id,
pos.company_id AS company_id,
NULL AS campaign_id,
NULL AS medium_id,
NULL AS source_id,
t.categ_id AS categ_id,
pos.pricelist_id AS pricelist_id,
pos.crm_team_id AS team_id,
p.product_tmpl_id,
partner.commercial_partner_id AS commercial_partner_id,
partner.country_id AS country_id,
partner.industry_id AS industry_id,
partner.state_id AS state_id,
partner.zip AS partner_zip,
(SUM(p.weight) * l.qty / u.factor) AS weight,
(SUM(p.volume) * l.qty / u.factor) AS volume,
l.discount AS discount,
SUM((l.price_unit * l.discount * l.qty / 100.0
/ {self._case_value_or_one('pos.currency_rate')}
* {self._case_value_or_one('account_currency_table.rate')}))
AS discount_amount,
concat('pos.order', ',', pos.id) AS order_reference"""
additional_fields = self._select_additional_fields()
additional_fields_info = self._fill_pos_fields(additional_fields)
template = """,
%s AS %s"""
for fname, value in additional_fields_info.items():
select_ += template % (value, fname)
return select_
def _available_additional_pos_fields(self):
"""Hook to replace the additional fields from sale with the one from pos_sale."""
return {
'warehouse_id': 'picking.warehouse_id',
}
def _fill_pos_fields(self, additional_fields):
"""Hook to fill additional fields for the pos_sale.
:param values: dictionary of values to fill
:type values: dict
"""
filled_fields = {x: 'NULL' for x in additional_fields}
for fname, value in self._available_additional_pos_fields().items():
if fname in additional_fields:
filled_fields[fname] = value
return filled_fields
def _from_pos(self):
currency_table = self.env['res.currency']._get_simple_currency_table(self.env.companies)
return """
pos_order_line l
JOIN pos_order pos ON l.order_id = pos.id
LEFT JOIN res_partner partner ON (pos.partner_id=partner.id OR pos.partner_id = NULL)
LEFT JOIN product_product p ON l.product_id=p.id
LEFT JOIN product_template t ON p.product_tmpl_id=t.id
LEFT JOIN uom_uom u ON u.id=t.uom_id
LEFT JOIN pos_session session ON session.id = pos.session_id
LEFT JOIN pos_config config ON config.id = session.config_id
LEFT JOIN stock_picking_type picking ON picking.id = config.picking_type_id
JOIN {currency_table} ON account_currency_table.company_id = pos.company_id
""".format(
currency_table=self.env.cr.mogrify(currency_table).decode(self.env.cr.connection.encoding),
)
def _where_pos(self):
return """
l.sale_order_line_id IS NULL"""
def _group_by_pos(self):
return """
l.order_id,
l.product_id,
l.price_unit,
l.discount,
l.qty,
t.uom_id,
t.categ_id,
pos.id,
pos.name,
pos.date_order,
pos.partner_id,
pos.user_id,
pos.state,
pos.company_id,
pos.pricelist_id,
p.product_tmpl_id,
partner.commercial_partner_id,
partner.country_id,
partner.industry_id,
partner.state_id,
partner.zip,
u.factor,
pos.crm_team_id,
account_currency_table.rate,
picking.warehouse_id"""
def _query(self):
res = super()._query()
return res + f"""UNION ALL (
SELECT {self._select_pos()}
FROM {self._from_pos()}
WHERE {self._where_pos()}
GROUP BY {self._group_by_pos()}
)
"""