16 Commits

Author SHA1 Message Date
0dac9f1ba9 fix: Update 7.6 2025-07-23 13:26:30 -03:00
316d0fe62d Add field Not Restaurant in user 2025-07-13 11:35:20 -05:00
b51c12eeb9 update 7.6 2025-06-06 23:32:40 -03:00
e81f8f44d3 Fix: Venta por Zona traduccion 2024-10-21 14:14:53 -05:00
83dcdddf1f Feat: Report Sale by Zone 2024-10-21 14:01:03 -05:00
535befbf4b Feat: Informe de Ventas Por Usuario 2024-10-21 12:16:07 -05:00
f05acd6484 Fix: Test expected_report 2024-10-21 09:46:20 -05:00
ec834ff7d9 Feat: Traducciones, Cambio en el Menu 2024-10-20 21:19:16 -05:00
c34f782480 Feat: Sale Fast Food Product by Pizza 2024-10-20 20:03:09 -05:00
2480d43167 Fix: SaleLineDelete para lineas de tipo line 2024-10-20 16:22:05 -05:00
18ffd2458c Feat: Impresion fe_qrcode y cufe 2024-10-20 16:15:03 -05:00
501d0ff776 Feat: credito view 2024-10-20 14:26:11 -05:00
047fce94d3 Feat: total_tip view 2024-10-20 14:22:34 -05:00
cec192af36 Feat: Se agrega total_tip 2024-10-20 14:20:12 -05:00
9cc0828696 Fix: ip_address 2024-10-20 13:55:48 -05:00
6d97f92fcd Fix: string ip_addres 2024-10-20 13:43:00 -05:00
20 changed files with 621 additions and 282 deletions

View File

@@ -1,5 +1,6 @@
from trytond.pool import Pool from trytond.pool import Pool
from . import product, sale, production, invoice, user, report_close_statement from . import (
product, sale, production, invoice, user, report_close_statement, report)
__all__ = ['register'] __all__ = ['register']
@@ -14,6 +15,10 @@ def register():
user.User, user.User,
production.Production, production.Production,
report_close_statement.ReportCloseStatementStart, report_close_statement.ReportCloseStatementStart,
report.ReportSaleProduct,
report.ReportSaleByUser,
report.ReportSaleByZone,
report.ReportSaleContext,
module='sale_fast_food', type_='model') module='sale_fast_food', type_='model')
Pool.register( Pool.register(
report_close_statement.PrintReportCloseStatement, report_close_statement.PrintReportCloseStatement,

View File

@@ -58,6 +58,98 @@ msgctxt "field:sale.print_cash_register.start,shop:"
msgid "Shop" msgid "Shop"
msgstr "Tienda" msgstr "Tienda"
msgctxt "field:sale_fast_food.report.context,from_date:"
msgid "From Date"
msgstr "Desde la Fecha"
msgctxt "field:sale_fast_food.report.context,to_date:"
msgid "To Date"
msgstr "Hasta la Fecha"
msgctxt "model:ir.action,name:act_report_sale_fast_food_product_pizza"
msgid "Pizzas Sold by Product"
msgstr "Pizzas Vendidas Por Producto"
msgctxt "model:ir.ui.menu,name:menu_sale_fast_food_pizza"
msgid "Pizzas Sold by Product"
msgstr "Pizzas Vendidas Por Producto"
msgctxt "model:ir.action,name:act_report_sale_fast_food_by_user"
msgid "Sales by User"
msgstr "Ventas Por Usuario"
msgctxt "model:ir.ui.menu,name:menu_sale_fast_food_by_user"
msgid "Sales by User"
msgstr "Ventas Por Usuario"
msgctxt "model:ir.action,name:act_report_sale_fast_food_zone"
msgid "Sales by Zone"
msgstr "Ventas Por Zona"
msgctxt "model:ir.ui.menu,name:menu_sale_fast_food_zone"
msgid "Sales by Zone"
msgstr "Ventas Por Zona"
msgctxt "field:sale_fast_food.reporting.product,product_pizza:"
msgid "Product"
msgstr "Pizza"
msgctxt "field:sale_fast_food.reporting.product,quantity:"
msgid "Quantity"
msgstr "Cantidad"
msgctxt "field:sale_fast_food.reporting.by_user,user:"
msgid "User"
msgstr "Usuario"
msgctxt "field:sale_fast_food.reporting.by_user,completed_sales:"
msgid "Completed Sales"
msgstr "# Ventas"
msgctxt "field:sale_fast_food.reporting.by_user,untaxed_amount:"
msgid "Untaxed Amount"
msgstr "Base Imponible"
msgctxt "field:sale_fast_food.reporting.by_user,tax_amount:"
msgid "Tax Amount"
msgstr "Impuestos"
msgctxt "field:sale_fast_food.reporting.by_user,total_amount:"
msgid "Total Amount"
msgstr "Total"
msgctxt "field:sale_fast_food.reporting.by_user,total_tip_amount:"
msgid "Total Tip Amount"
msgstr "Propinas"
msgctxt "field:sale_fast_food.reporting.zone,zone:"
msgid "Zone"
msgstr "Zona"
msgctxt "field:sale_fast_food.reporting.zone,table:"
msgid "Table"
msgstr "Mesa"
msgctxt "field:sale_fast_food.reporting.zone,completed_sales:"
msgid "Completed Sales"
msgstr "# Ventas"
msgctxt "field:sale_fast_food.reporting.zone,untaxed_amount:"
msgid "Untaxed Amount"
msgstr "Base Imponible"
msgctxt "field:sale_fast_food.reporting.zone,tax_amount:"
msgid "Tax Amount"
msgstr "Impuestos"
msgctxt "field:sale_fast_food.reporting.zone,total_amount:"
msgid "Total Amount"
msgstr "Total"
msgctxt "field:sale_fast_food.reporting.zone,total_tip_amount:"
msgid "Total Tip Amount"
msgstr "Propinas"
msgctxt "wizard_button:sale.print_cash_register,start,end:" msgctxt "wizard_button:sale.print_cash_register,start,end:"
msgid "Cancel" msgid "Cancel"
msgstr "Cancelar" msgstr "Cancelar"

View File

@@ -1,8 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of # This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms. # this repository contains the full copyright notices and license terms.
from decimal import Decimal # from decimal import Decimal
from trytond.pool import Pool, PoolMeta from trytond.pool import PoolMeta
from trytond.model import fields # from trytond.model import fields
BOM_CHANGES = ['bom', 'product', 'quantity', 'uom', 'warehouse', 'location', BOM_CHANGES = ['bom', 'product', 'quantity', 'uom', 'warehouse', 'location',
@@ -13,6 +13,7 @@ class Production(metaclass=PoolMeta):
"Production" "Production"
__name__ = 'production' __name__ = 'production'
"""
@fields.depends( @fields.depends(
'bom', 'product', 'uom', 'quantity', 'company', 'inputs', 'outputs', 'bom', 'product', 'uom', 'quantity', 'company', 'inputs', 'outputs',
methods=['_explode_move_values']) methods=['_explode_move_values'])
@@ -55,3 +56,4 @@ class Production(metaclass=PoolMeta):
move.unit_price = Decimal(0) move.unit_price = Decimal(0)
outputs.append(move) outputs.append(move)
self.outputs = outputs self.outputs = outputs
"""

280
report.py Normal file
View File

@@ -0,0 +1,280 @@
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool
from trytond.pyson import If, Eval
from sql import Literal, Null
from sql.aggregate import Min, Sum, Count
from sql.functions import CurrentTimestamp
from trytond.transaction import Transaction
import datetime
class ReportSaleContext(ModelView):
"""Contexto de reportes de miembros de familia"""
__name__ = 'sale_fast_food.report.context'
from_date = fields.Date(
"From Date",
domain=[
If(Eval('to_date') & Eval('from_date'),
('from_date', '<=', Eval('to_date')),
()),
If(Eval('from_date'),
('from_date', '<=', datetime.date.today()))
])
to_date = fields.Date(
"To Date",
domain=[
If(Eval('from_date') & Eval('to_date'),
('to_date', '>=', Eval('from_date')),
()),
If(Eval('to_date'),
('to_date', '<=', datetime.date.today()))
])
class ReportSaleAbstract(ModelSQL):
@classmethod
def table_query(cls):
from_item, tables = cls._joins()
final_query = from_item.select(
*cls._columns(tables),
where=cls._where(tables),
group_by=cls._group_by(tables)
)
return final_query
@classmethod
def _joins(cls):
pool = Pool()
tables = {}
Sale = pool.get('sale.sale')
tables['sale.sale'] = sale = Sale.__table__()
SaleLine = pool.get('sale.line')
tables['sale.line'] = sale_line = SaleLine.__table__()
ProductTemplate = pool.get('product.template')
tables[
'product.template'
] = product_template = ProductTemplate.__table__()
ProductProduct = pool.get('product.product')
tables['product.product'] = product = ProductProduct.__table__()
from_item = sale_line.left_join(
product,
condition=product.id == sale_line.product
).left_join(
product_template,
condition=product.template == product_template.id
).left_join(
sale,
condition=sale.id == sale_line.sale
)
return from_item, tables
@classmethod
def _columns(cls, tables):
columns = [
cls._column_id(tables).as_('id'),
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
cls.write_uid.sql_cast(Literal(Null)).as_('write_uid'),
cls.write_date.sql_cast(Literal(Null)).as_('write_date'),
]
return columns
@classmethod
def _where(cls, tables):
context = Transaction().context
where = Literal(True)
from_date = context.get('from_date')
to_date = context.get('to_date')
sale = tables['sale.sale']
if from_date:
where &= sale.sale_date >= from_date
if to_date:
where &= sale.sale_date <= to_date
return where
@classmethod
def _group_by(cls, tables):
raise NotImplementedError()
@classmethod
def _column_id(cls, tables):
sale_line = tables['sale.line']
return Min(sale_line.id)
class ReportSaleProduct(ReportSaleAbstract, ModelView):
"""Report Sale Group by Product"""
__name__ = 'sale_fast_food.reporting.product'
product_pizza = fields.Many2One('product.product', "Product")
quantity = fields.Float("Quantity")
@classmethod
def _columns(cls, tables):
sale_line = tables['sale.line']
return super(ReportSaleProduct, cls)._columns(tables) + [
sale_line.product.as_('product_pizza'),
Sum(sale_line.quantity).as_('quantity')
]
@classmethod
def _group_by(cls, tables):
sale_line = tables['sale.line']
return [
sale_line.product
]
@classmethod
def _where(cls, tables):
where = super(ReportSaleProduct, cls)._where(tables)
product_template = tables['product.template']
where &= product_template.pizza == Literal(True)
return where
class ReportSaleByUser(ReportSaleAbstract, ModelView):
"""Report Sale Group by User"""
__name__ = 'sale_fast_food.reporting.by_user'
user = fields.Many2One('res.user', "User")
completed_sales = fields.Integer("Completed Sales")
untaxed_amount = fields.Numeric(
"Untaxed Amount", digits='currency', readonly=True)
tax_amount = fields.Numeric(
"Tax Amount", digits='currency', readonly=True)
total_amount = fields.Numeric(
"Total Amount", digits='currency', readonly=True)
total_tip_amount = fields.Numeric(
"Total Tip Amount", digits='currency', readonly=True)
currency = fields.Many2One(
'currency.currency', 'Currency', required=True)
@classmethod
def _joins(cls):
pool = Pool()
tables = {}
Sale = pool.get('sale.sale')
tables['sale.sale'] = sale = Sale.__table__()
from_item = sale
return from_item, tables
@classmethod
def _columns(cls, tables):
sale = tables['sale.sale']
return super(ReportSaleByUser, cls)._columns(tables) + [
sale.create_uid.as_('user'),
Count(Literal(1)).as_('completed_sales'),
Sum(sale.untaxed_amount_cache).as_('untaxed_amount'),
Sum(sale.tax_amount_cache).as_('tax_amount'),
Sum(sale.total_amount_cache).as_('total_amount'),
Sum(sale.total_tip_cache).as_('total_tip_amount'),
sale.currency.as_('currency'),
]
@classmethod
def _group_by(cls, tables):
sale = tables['sale.sale']
return [
sale.create_uid,
sale.currency
]
@classmethod
def _column_id(cls, tables):
sale = tables['sale.sale']
return Min(sale.id)
class ReportSaleByZone(ReportSaleAbstract, ModelView):
"""Report Sale Group by Zone"""
__name__ = 'sale_fast_food.reporting.zone'
zone = fields.Many2One('sale.zone', "Zone")
table = fields.Many2One('sale.table', "Table")
completed_sales = fields.Integer("Completed Sales")
untaxed_amount = fields.Numeric(
"Untaxed Amount", digits='currency', readonly=True)
tax_amount = fields.Numeric(
"Tax Amount", digits='currency', readonly=True)
total_amount = fields.Numeric(
"Total Amount", digits='currency', readonly=True)
total_tip_amount = fields.Numeric(
"Total Tip Amount", digits='currency', readonly=True)
currency = fields.Many2One(
'currency.currency', 'Currency', required=True)
@classmethod
def _joins(cls):
pool = Pool()
tables = {}
Sale = pool.get('sale.sale')
tables['sale.sale'] = sale = Sale.__table__()
Table = pool.get('sale.table')
tables['sale.table'] = table = Table.__table__()
Zone = pool.get('sale.zone')
tables['sale.table'] = zone = Zone.__table__()
from_item = sale.left_join(
table,
condition=table.id == sale.table
).left_join(
zone,
condition=zone.id == table.zone
)
return from_item, tables
@classmethod
def _columns(cls, tables):
sale = tables['sale.sale']
return super(ReportSaleByZone, cls)._columns(tables) + [
sale.zone.as_('zone'),
sale.table.as_('table'),
Count(Literal(1)).as_('completed_sales'),
Sum(sale.untaxed_amount_cache).as_('untaxed_amount'),
Sum(sale.tax_amount_cache).as_('tax_amount'),
Sum(sale.total_amount_cache).as_('total_amount'),
Sum(sale.total_tip_cache).as_('total_tip_amount'),
sale.currency.as_('currency'),
]
@classmethod
def _group_by(cls, tables):
sale = tables['sale.sale']
return [
sale.zone,
sale.table,
sale.currency
]
@classmethod
def _column_id(cls, tables):
sale = tables['sale.sale']
return Min(sale.id)

103
report.xml Normal file
View File

@@ -0,0 +1,103 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="sale_fast_food_report_view_form">
<field name="model">sale_fast_food.report.context</field>
<field name="type">form</field>
<field name="name">sale_fast_food_report_context_form</field>
</record>
<!-- Report by Product-->
<record model="ir.ui.view" id="report_sale_fast_food_product_pizza_view_list">
<field name="model">sale_fast_food.reporting.product</field>
<field name="type">tree</field>
<field name="name">pizzas_sold_by_product_list</field>
</record>
<record model="ir.action.act_window" id="act_report_sale_fast_food_product_pizza">
<field name="name">Pizzas Sold by Product</field>
<field name="res_model">sale_fast_food.reporting.product</field>
<field name="context_model">sale_fast_food.report.context</field>
</record>
<record model="ir.action.act_window.view" id="act_report_sale_fast_food_product_pizza_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="report_sale_fast_food_product_pizza_view_list"/>
<field name="act_window" ref="act_report_sale_fast_food_product_pizza"/>
</record>
<!-- Report by Product-->
<record model="ir.ui.view" id="report_sale_fast_food_by_user_view_list">
<field name="model">sale_fast_food.reporting.by_user</field>
<field name="type">tree</field>
<field name="name">sales_by_user_list</field>
</record>
<record model="ir.action.act_window" id="act_report_sale_fast_food_by_user">
<field name="name">Sales by User</field>
<field name="res_model">sale_fast_food.reporting.by_user</field>
<field name="context_model">sale_fast_food.report.context</field>
</record>
<record model="ir.action.act_window.view" id="act_report_sale_fast_food_by_user_view1">
<field name="sequence" eval="20"/>
<field name="view" ref="report_sale_fast_food_by_user_view_list"/>
<field name="act_window" ref="act_report_sale_fast_food_by_user"/>
</record>
<!-- Report by Zone-->
<record model="ir.ui.view" id="report_sale_fast_food_zone_view_list">
<field name="model">sale_fast_food.reporting.zone</field>
<field name="type">tree</field>
<field name="name">sales_by_zone_list</field>
</record>
<record model="ir.action.act_window" id="act_report_sale_fast_food_zone">
<field name="name">Sales by Zone</field>
<field name="res_model">sale_fast_food.reporting.zone</field>
<field name="context_model">sale_fast_food.report.context</field>
</record>
<record model="ir.action.act_window.view" id="act_report_sale_fast_food_zone_view1">
<field name="sequence" eval="20"/>
<field name="view" ref="report_sale_fast_food_zone_view_list"/>
<field name="act_window" ref="act_report_sale_fast_food_zone"/>
</record>
<menuitem
name="Pizzas Sold by Product"
parent="sale.menu_reporting"
sequence="10"
id="menu_sale_fast_food_pizza"
icon="tryton-graph"/>
<menuitem
name="Sales by User"
parent="sale.menu_reporting"
sequence="20"
id="menu_sale_fast_food_by_user"
icon="tryton-graph"/>
<menuitem
name="Sales by Zone"
parent="sale.menu_reporting"
sequence="30"
id="menu_sale_fast_food_zone"
icon="tryton-graph"/>
<record model="ir.action.keyword" id="act_report_sale_fast_food_product_pizza_keyword1">
<field name="keyword">tree_open</field>
<field name="model" ref="menu_sale_fast_food_pizza"/>
<field name="action" ref="act_report_sale_fast_food_product_pizza"/>
</record>
<record model="ir.action.keyword" id="act_report_sale_fast_food_by_user_keyword1">
<field name="keyword">tree_open</field>
<field name="model" ref="menu_sale_fast_food_by_user"/>
<field name="action" ref="act_report_sale_fast_food_by_user"/>
</record>
<record model="ir.action.keyword" id="act_report_sale_fast_food_zone_keyword1">
<field name="keyword">tree_open</field>
<field name="model" ref="menu_sale_fast_food_zone"/>
<field name="action" ref="act_report_sale_fast_food_zone"/>
</record>
</data>
</tryton>

View File

@@ -5,7 +5,6 @@ this repository contains the full copyright notices and license terms. -->
<data> <data>
<record model="ir.action.report" id="report_close_statement"> <record model="ir.action.report" id="report_close_statement">
<field name="name">Close statement</field> <field name="name">Close statement</field>
<field name="model"></field>
<field name="report_name">sale.cash_register</field> <field name="report_name">sale.cash_register</field>
<field name="report">sale_fast_food/report/close_statement.fodt</field> <field name="report">sale_fast_food/report/close_statement.fodt</field>
<field name="template_extension">odt</field> <field name="template_extension">odt</field>

70
sale.py
View File

@@ -20,6 +20,12 @@ class Sale(metaclass=PoolMeta):
'get_amount') 'get_amount')
total_discount_cache = fields.Numeric( total_discount_cache = fields.Numeric(
"Total Discount cache", digits='currency') "Total Discount cache", digits='currency')
total_tip = fields.Function(
Monetary(
"Total Tip", digits='currency', currency='currency'),
'get_amount')
total_tip_cache = fields.Numeric(
"Total Tip cache", digits="currency")
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
@@ -42,6 +48,7 @@ class Sale(metaclass=PoolMeta):
self.tax_amount = Decimal('0.0') self.tax_amount = Decimal('0.0')
self.total_amount = Decimal('0.0') self.total_amount = Decimal('0.0')
self.total_discount = Decimal('0.0') self.total_discount = Decimal('0.0')
self.total_tip = Decimal('0.0')
if self.lines: if self.lines:
for line in self.lines: for line in self.lines:
@@ -52,6 +59,7 @@ class Sale(metaclass=PoolMeta):
self.tax_amount = self.currency.round(self.tax_amount) self.tax_amount = self.currency.round(self.tax_amount)
self.total_amount = self.untaxed_amount + self.tax_amount self.total_amount = self.untaxed_amount + self.tax_amount
if self.currency: if self.currency:
self.total_tip = self.currency.round(self.total_tip)
self.total_discount = self.currency.round(self.total_discount) self.total_discount = self.currency.round(self.total_discount)
self.total_amount = self.currency.round(self.total_amount) self.total_amount = self.currency.round(self.total_amount)
@@ -62,6 +70,7 @@ class Sale(metaclass=PoolMeta):
sale.tax_amount_cache = sale.tax_amount sale.tax_amount_cache = sale.tax_amount
sale.total_amount_cache = sale.total_amount sale.total_amount_cache = sale.total_amount
sale.total_discount_cache = sale.total_discount sale.total_discount_cache = sale.total_discount
sale.total_tip_cache = sale.total_tip
cls.save(sales) cls.save(sales)
@classmethod @classmethod
@@ -70,6 +79,7 @@ class Sale(metaclass=PoolMeta):
tax_amount = {} tax_amount = {}
total_amount = {} total_amount = {}
total_discount = {} total_discount = {}
total_tip = {}
if {'tax_amount', 'total_amount'} & set(names): if {'tax_amount', 'total_amount'} & set(names):
compute_taxes = True compute_taxes = True
else: else:
@@ -82,10 +92,10 @@ class Sale(metaclass=PoolMeta):
if (sale.state in cls._states_cached if (sale.state in cls._states_cached
and sale.untaxed_amount_cache is not None and sale.untaxed_amount_cache is not None
and sale.tax_amount_cache is not None and sale.tax_amount_cache is not None
and sale.total_amount_cache is not None and sale.total_amount_cache is not None):
and sale.total_discount_cache is not None):
untaxed_amount[sale.id] = sale.untaxed_amount_cache untaxed_amount[sale.id] = sale.untaxed_amount_cache
total_discount[sale.id] = sale.total_discount_cache total_discount[sale.id] = sale.total_discount_cache
total_tip[sale.id] = sale.total_tip_cache
if compute_taxes: if compute_taxes:
tax_amount[sale.id] = sale.tax_amount_cache tax_amount[sale.id] = sale.tax_amount_cache
total_amount[sale.id] = sale.total_amount_cache total_amount[sale.id] = sale.total_amount_cache
@@ -94,8 +104,16 @@ class Sale(metaclass=PoolMeta):
(line.amount for line in sale.lines (line.amount for line in sale.lines
if line.type == 'line'), Decimal(0)), 2) if line.type == 'line'), Decimal(0)), 2)
total_discount[sale.id] = round(sum( total_discount[sale.id] = round(sum(
(line.discount_amount for line in sale.lines (line.discount_amount * Decimal(
if line.type == 'line'), Decimal(0)), 2) line.quantity) for line in sale.lines
if line.discount_amount and line.type == 'line'
), Decimal(0)), 2)
total_tip[sale.id] = round(
sum((
line.amount for line in sale.lines
if line.product and line.product.tip and (
line.type == 'line')
), Decimal(0)), 2)
if compute_taxes: if compute_taxes:
tax_amount[sale.id] = sale.get_tax_amount() tax_amount[sale.id] = sale.get_tax_amount()
total_amount[sale.id] = ( total_amount[sale.id] = (
@@ -106,6 +124,7 @@ class Sale(metaclass=PoolMeta):
'tax_amount': tax_amount, 'tax_amount': tax_amount,
'total_amount': total_amount, 'total_amount': total_amount,
'total_discount': total_discount, 'total_discount': total_discount,
'total_tip': total_tip
} }
for key in list(result.keys()): for key in list(result.keys()):
if key not in names: if key not in names:
@@ -149,8 +168,11 @@ class Sale(metaclass=PoolMeta):
data = {} data = {}
shop = Shop.search([('id', '=', ctx["shop"])])[0] shop = Shop.search([('id', '=', ctx["shop"])])[0]
data["shop_name"] = shop.name data["shop_name"] = shop.name
data["shop_nit"] = shop.company.party.tax_identifier.code
data["shop_address"] = shop.address.street data["shop_address"] = shop.address.street
data['invoice'] = cls.get_invoice(record) data['invoice'] = cls.get_invoice(record)
data['fe_cufe'] = record.fe_qrcode
data['cufe'] = record.fe_cufe
data["party"] = record.party.name data["party"] = record.party.name
data["tax_identifier_type"] = record.party.tax_identifier.type_string data["tax_identifier_type"] = record.party.tax_identifier.type_string
data["tax_identifier_code"] = record.party.tax_identifier.code data["tax_identifier_code"] = record.party.tax_identifier.code
@@ -172,6 +194,7 @@ class Sale(metaclass=PoolMeta):
data["total_discount"] = str(round(record.total_discount, 2)) data["total_discount"] = str(round(record.total_discount, 2))
data["untaxed_amount"] = str(record.untaxed_amount) data["untaxed_amount"] = str(record.untaxed_amount)
data["tax_amount"] = str(record.tax_amount) data["tax_amount"] = str(record.tax_amount)
data["total_tip"] = str(record.total_tip)
data["total"] = str(record.total_amount) data["total"] = str(record.total_amount)
data["state"] = \ data["state"] = \
"SUBTOTAL" if record.state == "draft" else "CUENTA FINAL" "SUBTOTAL" if record.state == "draft" else "CUENTA FINAL"
@@ -197,23 +220,17 @@ class Sale(metaclass=PoolMeta):
data["zone"] = report.zone.name if report.zone else "" data["zone"] = report.zone.name if report.zone else ""
data["table"] = report.table.name if report.table else "" data["table"] = report.table.name if report.table else ""
data["lines"] = [{ data["lines"] = [{
'type': line.type, "type": line.type,
"product": line.product.name if line.type != 'title' else None, "product": line.product.name if line.type != "title" else None,
"description": line.description if line.type != 'title' else None, "description": line.description if line.type != "title" else None,
"quantity": line.quantity if line.type != 'title' else None, "quantity": line.quantity if line.type != "title" else None,
"uom": line.unit.name if line.type != 'title' else None} "uom": line.unit.name if line.type != "title" else None}
for line in report.lines if not line.impreso] for line in report.lines if not line.impreso]
data["deleted_lines"] = [{ data["deleted_lines"] = [{
<<<<<<< HEAD
"product": line.product.name, "product": line.product.name,
"quantity": str(-1 * line.quantity), "quantity": str(-1 * line.quantity),
"unit": line.unit.symbol, "unit": line.unit.symbol
} for line in report.delete_lines if not line.printed] } for line in report.delete_lines if not line.printed]
=======
"product": line.product.name if line.type != 'title' else None,
"quantity": line.quantity if line.type != 'title' else None,
} for line in report.delete_lines if not line.impreso]
>>>>>>> 77d626374f847b8e54b81cc06f76b545e4014b29
return data return data
@@ -238,11 +255,7 @@ class Sale(metaclass=PoolMeta):
line.save() line.save()
for line in record.delete_lines: for line in record.delete_lines:
<<<<<<< HEAD
line.printed = True line.printed = True
=======
line.impreso = True
>>>>>>> 77d626374f847b8e54b81cc06f76b545e4014b29
line.save() line.save()
record.save() record.save()
@@ -278,7 +291,7 @@ class Sale(metaclass=PoolMeta):
if printer.type_ == 'network': if printer.type_ == 'network':
content["printer_type"] = "Network" content["printer_type"] = "Network"
content["ip_printer"] = str(printer.ip_address), content["ip_printer"] = str(printer.ip_address)
else: else:
if printer.type_ == 'usb': if printer.type_ == 'usb':
content["printer_type"] = "USB" content["printer_type"] = "USB"
@@ -321,7 +334,7 @@ class Sale(metaclass=PoolMeta):
if printer.type_ == 'network': if printer.type_ == 'network':
content["printer_type"] = "Network" content["printer_type"] = "Network"
content["ip_printer"] = str(printer.ip_address), content["ip_printer"] = str(printer.ip_address)
else: else:
if printer.type_ == 'usb': if printer.type_ == 'usb':
content["printer_type"] = "USB" content["printer_type"] = "USB"
@@ -333,8 +346,8 @@ class Sale(metaclass=PoolMeta):
cls.impreso([record]) cls.impreso([record])
requests.post( requests.post(
url, data=json.dumps(content), url, data=str(json.dumps(content)),
headers=headers, timeout=5) headers=headers)
@classmethod @classmethod
@ModelView.button @ModelView.button
@@ -370,7 +383,7 @@ class Sale(metaclass=PoolMeta):
if printer.type_ == 'network': if printer.type_ == 'network':
content["printer_type"] = "Network" content["printer_type"] = "Network"
content["ip_printer"] = str(printer.ip_address), content["ip_printer"] = str(printer.ip_address)
else: else:
if printer.type_ == 'usb': if printer.type_ == 'usb':
content["printer_type"] = "USB" content["printer_type"] = "USB"
@@ -395,19 +408,20 @@ class Line(metaclass=PoolMeta):
@classmethod @classmethod
def delete(cls, lines): def delete(cls, lines):
for line in lines: for line in lines:
if line.impreso: if line.impreso and line.type == 'line':
cls._create_sale_line_deleted_log(line) cls._create_sale_line_deleted_log(line)
super(Line, cls).delete(lines) super(Line, cls).delete(lines)
@fields.depends('product', 'unit', 'sale', @fields.depends('product', 'unit', 'sale',
'_parent_sale.party', '_parent_sale.invoice_party', '_parent_sale.party', '_parent_sale.invoice_party',
'_parent_sale.pizza_number', '_parent_sale.pizza_number',
'_parent_product.pizza', '_parent_product.template',
'_parent_product._parent_template.pizza',
methods=['compute_taxes', 'compute_unit_price', methods=['compute_taxes', 'compute_unit_price',
'on_change_with_amount']) 'on_change_with_amount'])
def on_change_product(self): def on_change_product(self):
super(Line, self).on_change_product() super(Line, self).on_change_product()
if self.product and self.product.pizza: if self.product and self.product.template.pizza:
self.pizza = self.sale.pizza_number self.pizza = self.sale.pizza_number
self.bought_pizza = True self.bought_pizza = True
else: else:

View File

@@ -21,27 +21,27 @@
<record model="ir.model.button" id="sale_add_pizza_button"> <record model="ir.model.button" id="sale_add_pizza_button">
<field name="name">add_pizza</field> <field name="name">add_pizza</field>
<field name="string">Add Pizza</field> <field name="string">Add Pizza</field>
<field name="model" search="[('model', '=', 'sale.sale')]"/> <field name="model">sale.sale</field>
</record> </record>
<record model="ir.model.button" id="sale_order_kitchen_button"> <record model="ir.model.button" id="sale_order_kitchen_button">
<field name="name">kitchen</field> <field name="name">kitchen</field>
<field name="string">Kitchen</field> <field name="string">Kitchen</field>
<field name="model" search="[('model', '=', 'sale.sale')]"/> <field name="model">sale.sale</field>
</record> </record>
<record model="ir.model.button" id="sale_order_bar_button"> <record model="ir.model.button" id="sale_order_bar_button">
<field name="name">bar</field> <field name="name">bar</field>
<field name="string">Bar</field> <field name="string">Bar</field>
<field name="model" search="[('model', '=', 'sale.sale')]"/> <field name="model">sale.sale</field>
</record> </record>
<record model="ir.model.button" id="sale_print_bill_button"> <record model="ir.model.button" id="sale_print_bill_button">
<field name="name">print_bill</field> <field name="name">print_bill</field>
<field name="string">Bill</field> <field name="string">Bill</field>
<field name="model" search="[('model', '=', 'sale.sale')]"/> <field name="model">sale.sale</field>
</record> </record>
<record model="ir.model.button" id="sale_impreso_button"> <record model="ir.model.button" id="sale_impreso_button">
<field name="name">impreso</field> <field name="name">impreso</field>
<field name="string">Impreso</field> <field name="string">Impreso</field>
<field name="model" search="[('model', '=', 'sale.sale')]"/> <field name="model">sale.sale</field>
</record> </record>
<record model="ir.action.report" id="report_customer_order"> <record model="ir.action.report" id="report_customer_order">
<field name="name">Customer Order</field> <field name="name">Customer Order</field>

View File

@@ -1,209 +0,0 @@
=============================
Sale Line Delete Log Scenario
=============================
Imports::
>>> from decimal import Decimal
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, get_company
>>> from trytond.modules.account.tests.tools import (
... create_chart, create_fiscalyear, create_tax, get_accounts)
>>> from trytond.modules.account_invoice.tests.tools import (
... create_payment_term, set_fiscalyear_invoice_sequences)
>>> import datetime as dt
>>> today = dt.date.today()
>>> from trytond.tests.tools import set_user
>>> from trytond.modules.sale_shop.tests.tools import create_shop
>>> from trytond.modules.sale_line_delete_log.sale import SaleLineDeleted
Activate modules::
>>> config = activate_modules('sale_fast_food')
Initial data::
>>> User = Model.get('res.user')
>>> Party = Model.get('party.party')
>>> Employee = Model.get('company.employee')
>>> Journal = Model.get('account.journal')
>>> PaymentMethod = Model.get('account.invoice.payment.method')
>>> Party = Model.get('party.party')
>>> ProductUom = Model.get('product.uom')
>>> ProductTemplate = Model.get('product.template')
>>> Sale = Model.get('sale.sale')
>>> SaleLine = Model.get('sale.line')
Create company::
>>> _ = create_company()
>>> company = get_company()
Set employee::
>>> employee_party = Party(name="Employee")
>>> employee_party.save()
>>> employee = Employee(party=employee_party)
>>> employee.save()
>>> user = User(config.user)
>>> user.employees.append(employee)
>>> user.employee = employee
>>> user.save()
>>> set_user(user.id)
Create fiscal year::
>>> fiscalyear = set_fiscalyear_invoice_sequences(create_fiscalyear(company, today))
>>> fiscalyear.click('create_period')
Create chart of accounts::
>>> _ = create_chart(company)
>>> accounts = get_accounts(company)
>>> revenue = accounts['revenue']
>>> expense = accounts['expense']
>>> cash = accounts['cash']
>>> cash_journal, = Journal.find([('type', '=', 'cash')])
>>> cash_journal.save()
>>> payment_method = PaymentMethod()
>>> payment_method.name = 'Cash'
>>> payment_method.journal = cash_journal
>>> payment_method.credit_account = cash
>>> payment_method.debit_account = cash
>>> payment_method.save()
Create tax::
>>> tax = create_tax(Decimal('.10'))
>>> tax.save()
Create parties::
>>> supplier = Party(name='Supplier')
>>> supplier.save()
>>> customer = Party(name='Customer')
>>> customer.save()
Create account categories::
>>> ProductCategory = Model.get('product.category')
>>> account_category = ProductCategory(name="Account Category")
>>> account_category.accounting = True
>>> account_category.account_expense = expense
>>> account_category.account_revenue = revenue
>>> account_category.save()
>>> account_category_tax, = account_category.duplicate()
>>> account_category_tax.customer_taxes.append(tax)
>>> account_category_tax.save()
Create product::
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> template = ProductTemplate()
>>> template.name = 'product'
>>> template.default_uom = unit
>>> template.type = 'goods'
>>> template.salable = True
>>> template.list_price = Decimal('10')
>>> template.account_category = account_category_tax
>>> template.save()
>>> product, = template.products
>>> template = ProductTemplate()
>>> template.name = 'service'
>>> template.default_uom = unit
>>> template.type = 'service'
>>> template.salable = True
>>> template.list_price = Decimal('30')
>>> template.account_category = account_category
>>> template.save()
>>> service, = template.products
Create payment term::
>>> payment_term = create_payment_term()
>>> payment_term.save()
Create product price list::
>>> ProductPriceList = Model.get('product.price_list')
>>> product_price_list = ProductPriceList()
>>> product_price_list.name = 'Price List'
>>> product_price_list.company = company
>>> product_price_list.save()
Create an Inventory::
>>> Inventory = Model.get('stock.inventory')
>>> Location = Model.get('stock.location')
>>> storage, = Location.find([
... ('code', '=', 'STO'),
... ])
>>> inventory = Inventory()
>>> inventory.location = storage
>>> inventory_line = inventory.lines.new(product=product)
>>> inventory_line.quantity = 100.0
>>> inventory_line.expected_quantity = 0.0
>>> inventory.click('confirm')
>>> inventory.state
'done'
Create Sale Shop::
>>> shop = create_shop(payment_term, product_price_list)
>>> shop.save()
Save Sale Shop User::
>>> User = Model.get('res.user')
>>> user, = User.find([])
>>> user.shops.append(shop)
>>> user.shop = shop
>>> user.save()
>>> set_user(user)
Sale 5 products::
>>> sale = Sale()
>>> sale.party = customer
>>> sale.payment_term = payment_term
>>> sale.invoice_method = 'order'
>>> sale_line = SaleLine()
>>> sale.lines.append(sale_line)
>>> sale_line.product = product
>>> sale_line.quantity = 2.0
>>> sale_line.impreso = True
>>> sale_line = SaleLine()
>>> sale.lines.append(sale_line)
>>> sale_line.type = 'comment'
>>> sale_line.description = 'Comment'
>>> sale_line = SaleLine()
>>> sale.lines.append(sale_line)
>>> sale_line.product = product
>>> sale_line.quantity = 3.0
>>> sale.save()
>>> len(sale.lines)
3
>>> sale.untaxed_amount, sale.tax_amount, sale.total_amount
(Decimal('50.00'), Decimal('5.00'), Decimal('55.00'))
Create a sale line delete log it's was printed::
>>> sale.reload()
>>> sale.lines[0].delete()
>>> sale.lines[1].delete()
>>> sale.save()
>>> len(sale.lines)
1
>>> sale.reload()
>>> len(sale.delete_lines)
1
>>> sale.delete_lines[0]
proteus.Model.get('sale.line_deleted')(1)
>>> assert isinstance(sale.delete_lines[0], Model.get('sale.line_deleted')), "it's not instance SaleLineDeleted"

View File

@@ -1,5 +1,5 @@
[tryton] [tryton]
version=6.8.0 version=7.6.0
depends: depends:
ir ir
res res
@@ -18,3 +18,4 @@ xml:
sale.xml sale.xml
user.xml user.xml
report_close_statement.xml report_close_statement.xml
report.xml

View File

@@ -7,3 +7,4 @@ class User(metaclass=PoolMeta):
__name__ = 'res.user' __name__ = 'res.user'
waiter = fields.Boolean('Waiter') waiter = fields.Boolean('Waiter')
not_restaurant = fields.Boolean('Not Restaurant')

View File

@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="product_pizza"/>
<field name="quantity" sum="1"/>
</tree>

View File

@@ -13,8 +13,11 @@
<field name="kitchen"/> <field name="kitchen"/>
<label name="bar"/> <label name="bar"/>
<field name="bar"/> <field name="bar"/>
<newline/> </xpath>
<xpath expr="//field[@name='default_uom']" position="after">
<group id="boms">
<label name="boms"/> <label name="boms"/>
<field name="boms" xexpand="1"/> <field name="boms"/>
</group>
</xpath> </xpath>
</data> </data>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form>
<label name="from_date"/>
<group id="dates" col="-1">
<field name="from_date"/>
<label name="to_date"/>
<field name="to_date"/>
</group>
</form>

View File

@@ -16,6 +16,11 @@ this repository contains the full copyright notices and license terms. -->
position="after"> position="after">
<label name="total_discount"/> <label name="total_discount"/>
<field name="total_discount"/> <field name="total_discount"/>
<label name="total_tip"/>
<field name="total_tip"/>
</xpath>
<xpath expr="/form/notebook/page[@id='sale']/group[@id='amount']/field[@name='total_amount']"
position="after">
<label name="credito"/> <label name="credito"/>
<field name="credito"/> <field name="credito"/>
</xpath> </xpath>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="user"/>
<field name="completed_sales" sum="1"/>
<field name="untaxed_amount" sum="1"/>
<field name="tax_amount" sum="1"/>
<field name="total_amount" sum="1"/>
<field name="total_tip_amount" sum="1"/>
</tree>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree>
<field name="zone"/>
<field name="table"/>
<field name="completed_sales" sum="1"/>
<field name="untaxed_amount" sum="1"/>
<field name="tax_amount" sum="1"/>
<field name="total_amount" sum="1"/>
<field name="total_tip_amount" sum="1"/>
</tree>

View File

@@ -5,5 +5,7 @@
<xpath expr="//field[@name='name']" position="after"> <xpath expr="//field[@name='name']" position="after">
<label name="waiter"/> <label name="waiter"/>
<field name="waiter"/> <field name="waiter"/>
<label name="not_restaurant"/>
<field name="not_restaurant"/>
</xpath> </xpath>
</data> </data>