trytonpsk-sale_pos/shop.py

603 lines
24 KiB
Python
Raw Permalink Normal View History

2020-04-15 21:47:31 +02:00
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from decimal import Decimal
from datetime import time, datetime, timedelta
from sql import Null
from sql.aggregate import Sum
2020-04-15 21:47:31 +02:00
from trytond.model import fields, ModelView
2020-09-26 19:15:42 +02:00
from trytond.pyson import Eval
2020-04-15 21:47:31 +02:00
from trytond.pool import PoolMeta, Pool
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, Button, StateReport
from trytond.report import Report
_ZERO = Decimal(0)
class SaleShop(metaclass=PoolMeta):
__name__ = 'sale.shop'
party = fields.Many2One('party.party', 'Default Party')
invoice_sequence = fields.Many2One('ir.sequence.strict', 'Invoice Sequence')
2023-10-21 01:54:42 +02:00
credit_note_sequence = fields.Many2One('ir.sequence.strict',
'Credit Note Sequence')
2023-10-26 21:34:18 +02:00
# self_pick_up = fields.Boolean('Default Self Pick Up',
# help='The goods are picked up by the customer before the sale, so no '
# 'shipment is created.')
2023-10-21 01:54:42 +02:00
pos_authorization = fields.Many2One('account.invoice.authorization',
'POS Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', '=', 'P'),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
computer_authorization = fields.Many2One('account.invoice.authorization', 'Computer Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', '=', 'C'),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
electronic_authorization = fields.Many2One('account.invoice.authorization', 'Electronic Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', 'in', ['1', '2', '3']),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
credit_note_electronic_authorization = fields.Many2One('account.invoice.authorization', 'Credit Note Electronic Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', '=', '91'),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
debit_note_electronic_authorization = fields.Many2One('account.invoice.authorization', 'Debit Note Electronic Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', '=', '92'),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
manual_authorization = fields.Many2One('account.invoice.authorization', 'Manual Authorization', domain=[
2020-09-26 19:15:42 +02:00
('kind', '=', 'M'),
('company', '=', Eval('company')),
2020-04-15 21:47:31 +02:00
])
2020-05-26 22:52:51 +02:00
freight_product = fields.Many2One('product.product', 'Freight Product')
email_template = fields.Many2One('email.template', 'Template')
2020-04-15 21:47:31 +02:00
class ShopDailySummaryStart(ModelView):
'Shop Daily Summary Start'
__name__ = 'sale_pos.shop_daily_summary.start'
company = fields.Many2One('company.company', 'Company', required=True)
sale_date = fields.Date('Sale Date', required=True)
shop = fields.Many2One('sale.shop', 'Shop', required=True)
early_morning_included = fields.Boolean('Early Morning Included')
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_sale_date():
Date = Pool().get('ir.date')
return Date.today()
class ShopDailySummary(Wizard):
'Shop Daily Summary'
__name__ = 'sale_pos.shop_daily_summary'
start = StateView('sale_pos.shop_daily_summary.start',
'sale_pos.shop_daily_summary_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('sale_pos.shop_daily_summary_report')
def do_print_(self, action):
report_context = {
2021-06-22 20:38:42 +02:00
'ids': [],
2020-04-15 21:47:31 +02:00
'company': self.start.company.id,
'sale_date': self.start.sale_date,
'shop': self.start.shop.id,
'early_morning_included': self.start.early_morning_included,
}
return action, report_context
def transition_print_(self):
return 'end'
class ShopDailySummaryReport(Report):
'Shop Daily Summary'
__name__ = 'sale_pos.shop_daily_summary_report'
@classmethod
def get_query(cls, data, products_exception):
pool = Pool()
Sale = pool.get('sale.sale')
Line = pool.get('sale.line')
Invoice = pool.get('account.invoice')
Company = pool.get('company.company')
2023-10-21 01:54:42 +02:00
fixed_hour = time(6, 0)
cursor = Transaction().connection.cursor()
sale = Sale.__table__()
line = Line.__table__()
result_ = {}
where_ = sale.state.in_(['processing', 'done'])
where_ = line.product.in_(products_exception)
where_ &= sale.company == data['company']
where_ &= sale.invoice_type == 'P'
where_ &= sale.number != Null
if data['shop']:
where_ &= sale.shop == data['shop']
if not data['early_morning_included']:
where_ &= sale.invoice_date == data['sale_date']
else:
# Select sales including early morning of next day
_start_date = datetime.combine(data['sale_date'], fixed_hour)
_start_date = Company.convert_timezone(_start_date, True)
end_date = data['sale_date'] + timedelta(days=1)
_end_date = datetime.combine(end_date, fixed_hour)
_end_date = Company.convert_timezone(_end_date, True)
where_ &= sale.sale_date >= data['sale_date']
where_ &= sale.sale_date <= end_date
where_ &= sale.create_date >= _start_date
where_ &= sale.create_date <= _end_date
columns_ = [sale.id, Sum(line.unit_price*line.quantity).as_('amount')]
query = line.join(sale, condition=line.sale==sale.id).select(*columns_,
where=where_,
group_by=sale.id)
cursor.execute(*query)
columns = list(cursor.description)
result = cursor.fetchall()
for row in result:
result_[row[0]] = row[1]
return result_
2020-04-15 21:47:31 +02:00
@classmethod
2021-06-22 20:38:42 +02:00
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
2020-04-15 21:47:31 +02:00
pool = Pool()
Sale = pool.get('sale.sale')
Company = pool.get('company.company')
company = Company(data['company'])
Shop = pool.get('sale.shop')
Tax = pool.get('account.tax')
Device = pool.get('sale.device')
fixed_hour = time(6, 0)
config = pool.get('sale.configuration')(1)
products_exception = []
amount_exception = {}
if hasattr(config, 'tip_product') and config.tip_product and config.exclude_tip_and_delivery:
products_exception.append(config.tip_product.id)
if hasattr(config, 'delivery_product') and config.delivery_product and config.exclude_tip_and_delivery:
products_exception.append(config.delivery_product.id)
if products_exception:
amount_exception = cls.get_query(data, products_exception)
2020-04-15 21:47:31 +02:00
dom_sales = [
('shop', '=', data['shop']),
('company', '=', data['company']),
('number', '!=', None),
('invoice_type', '=', 'P'),
2020-04-15 21:47:31 +02:00
]
if not data['early_morning_included']:
dom_sales.append(('sale_date', '=', data['sale_date']))
else:
# Select sales including early morning of next day
_start_date = datetime.combine(data['sale_date'], fixed_hour)
_start_date = Company.convert_timezone(_start_date, True)
end_date = data['sale_date'] + timedelta(days=1)
_end_date = datetime.combine(end_date, fixed_hour)
_end_date = Company.convert_timezone(_end_date, True)
dom_sales.append(('sale_date', '>=', data['sale_date']))
dom_sales.append(('sale_date', '<=', end_date))
dom_sales.append(('create_date', '>=', _start_date))
dom_sales.append(('create_date', '<=', _end_date))
states_sale = ['processing', 'done']
dom_sales.append(('state', 'in', states_sale))
sales = Sale.search(dom_sales, order=[('number', 'ASC')])
untaxed_amount = []
tax_amount = []
total_amount = []
devices_ = Device.search([
('shop', '=', data['shop'])
])
devices = {}
for d in devices_:
devices[d.id] = {
'name': d.name,
'code': d.code,
'count_invoices': 0,
'untaxed_amount': [],
'tax_amount': [],
'total_amount': [],
'cash': [],
'credit': [],
'electronic': [],
'other': [],
}
payment_modes = {
'cash': [],
'credit': [],
2020-04-15 21:47:31 +02:00
'electronic': [],
'other': [],
}
numbers = []
categories = {}
2021-09-07 15:41:35 +02:00
discounts = {}
_payments = {}
2021-09-07 15:41:35 +02:00
total_discount = []
total_payments = []
2020-04-15 21:47:31 +02:00
for sale in sales:
payments = sale.payments
sale_id = sale.id
device_id = None
try:
value_except = Decimal(amount_exception[sale_id])
except:
value_except= Decimal(0)
if sale.sale_device:
device_id = sale.sale_device.id
2020-04-15 21:47:31 +02:00
if sale.total_amount <= 0:
continue
if not sale.invoices:
continue
invoice = sale.invoices[0]
if not invoice.number or invoice.total_amount <= 0 or not device_id:
continue
numbers.append(invoice.number)
untaxed_ammount_ = invoice.untaxed_amount - value_except
total_amount_ = invoice.total_amount - value_except
devices[device_id]['count_invoices'] += 1
devices[device_id]['untaxed_amount'].append(untaxed_ammount_)
devices[device_id]['tax_amount'].append(invoice.tax_amount)
devices[device_id]['total_amount'].append(total_amount_)
untaxed_amount.append(untaxed_ammount_)
2020-04-15 21:47:31 +02:00
tax_amount.append(invoice.tax_amount)
total_amount.append(total_amount_)
if payments:
amount_by_sale = []
for payment in payments:
kind = payment.statement.journal.kind
amount = payment.amount
if value_except > 0 and payment.amount > value_except:
amount = payment.amount - value_except
value_except = 0
amount_by_sale.append(amount)
if kind not in ['cash', 'credit', 'electronic']:
2020-04-15 21:47:31 +02:00
kind = 'other'
devices[device_id][kind].append(amount)
payment_modes[kind].append(amount)
2021-09-07 15:41:35 +02:00
journal = payment.statement.journal
try:
_payments[journal.id]['amount'].append(amount)
except:
_payments[journal.id] = {
2021-09-07 15:41:35 +02:00
'name': journal.name,
'amount': [amount],
2021-09-07 15:41:35 +02:00
}
total_payments.append(amount)
2021-09-07 15:41:35 +02:00
amount_to_pay = invoice.amount_to_pay
if amount_to_pay > 0:
# THIS MUST WORKS IN FUTURE WITH ADD PAYMENT INSTATEMENT TO INVOICE
# devices[device_id]['credit'].append(amount_to_pay)
# payment_modes['credit'].append(amount_to_pay)
# FIX TEMPORAL
inv_balance = invoice.total_amount - sum(amount_by_sale)
devices[device_id]['credit'].append(inv_balance)
payment_modes['credit'].append(inv_balance)
2020-04-15 21:47:31 +02:00
else:
devices[sale.sale_device.id]['credit'].append(total_amount_)
if value_except > 0:
payment_modes['credit'].append(invoice.amount_to_pay - value_except)
else:
payment_modes['credit'].append(invoice.amount_to_pay)
2020-04-15 21:47:31 +02:00
for line in invoice.lines:
category_id = '0'
if line.product.id in products_exception:
continue
2020-04-15 21:47:31 +02:00
if line.product.account_category:
category = line.product.account_category
2021-09-07 15:41:35 +02:00
category_id = category.id
if category_id not in categories.keys():
categories[category_id] = {
'name': category.name,
'base': [line.amount],
'taxes': {},
}
2022-01-15 00:00:16 +01:00
if line.taxes and line.amount:
for t in line.taxes:
categories[category_id]['taxes'][t.id] = {
'tax': [t],
'base': [line.amount],
}
2021-09-07 15:41:35 +02:00
else:
2022-01-15 00:00:16 +01:00
if line.taxes and line.amount:
for t in line.taxes:
try:
categories[category_id]['taxes'][t.id]['base'].append(line.amount)
except:
categories[category_id]['taxes'][t.id] = {
'tax': [t],
'base': [line.amount],
}
2021-09-07 15:41:35 +02:00
categories[category_id]['base'].append(line.amount)
if line.discount:
2021-09-11 17:19:34 +02:00
try:
disc = line.amount / (1 - line.discount)
except:
2021-10-07 02:19:18 +02:00
disc = line.product.template.list_price * Decimal(line.quantity)
2021-09-07 15:48:07 +02:00
if category_id not in discounts.keys():
2021-09-07 15:41:35 +02:00
discounts[category_id] = {
2020-04-15 21:47:31 +02:00
'name': category.name,
2021-09-07 15:41:35 +02:00
'amount': [disc],
2020-04-15 21:47:31 +02:00
}
2021-09-07 15:41:35 +02:00
else:
discounts[category_id]['amount'].append(disc)
total_discount.append(disc)
2020-04-15 21:47:31 +02:00
for k, v in categories.items():
base = sum(v['base'])
categories[k]['base'] = base
2022-01-15 00:00:16 +01:00
taxes = categories[k]['taxes']
if len(taxes) > 0:
for t, m in categories[k]['taxes'].items():
tax_list = Tax.compute(m['tax'], sum(m['base']), 1)
categories[k]['taxes'][t].update({
'name': tax_list[0]['tax'].name,
'base': sum(m['base']),
'amount': tax_list[0]['amount']
})
2020-04-15 21:47:31 +02:00
else:
categories[k]['taxes'][0] = {
'name': 'EXCLUIDOS / EXENTOS',
'base': base,
'amount': _ZERO
}
if numbers:
min_number = min(numbers)
max_number = max(numbers)
else:
min_number = ''
max_number = ''
report_context['date'] = data['sale_date']
2023-04-19 19:16:46 +02:00
report_context['company'] = company
2020-04-15 21:47:31 +02:00
report_context['shop'] = Shop(data['shop']).name
report_context['start_number'] = min_number
report_context['end_number'] = max_number
report_context['records'] = devices.values()
report_context['categories'] = categories.values()
report_context['sum_count_invoices'] = len(numbers)
report_context['sum_untaxed_amount'] = sum(untaxed_amount)
report_context['sum_tax_amount'] = sum(tax_amount)
report_context['sum_total_amount'] = sum(total_amount)
2021-09-07 15:41:35 +02:00
report_context['discounts'] = discounts.values()
report_context['total_discount'] = sum(total_discount)
report_context['payments'] = _payments.values()
2021-09-07 15:41:35 +02:00
report_context['total_payments'] = sum(total_payments)
2020-04-15 21:47:31 +02:00
report_context['sum_cash'] = sum(payment_modes['cash'])
report_context['sum_credit'] = sum(payment_modes['credit'])
report_context['sum_electronic'] = sum(payment_modes['electronic'])
report_context['sum_other'] = sum(payment_modes['other'])
return report_context
2023-04-20 21:39:06 +02:00
class ShopDailyCategoryStart(ModelView):
'Shop Daily Summary Start'
__name__ = 'sale_pos.shop_daily_category.start'
company = fields.Many2One('company.company', 'Company', required=True)
sale_date = fields.Date('Sale Date', required=True)
end_date = fields.Date('End Date')
2023-04-20 21:39:06 +02:00
shop = fields.Many2One('sale.shop', 'Shop', required=True)
early_morning_included = fields.Boolean('Early Morning Included')
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_sale_date():
Date = Pool().get('ir.date')
return Date.today()
class ShopDailyCategory(Wizard):
'Shop Daily Summary'
__name__ = 'sale_pos.shop_daily_category'
start = StateView('sale_pos.shop_daily_category.start',
'sale_pos.shop_daily_category_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('sale_pos.shop_daily_category_report')
def do_print_(self, action):
report_context = {
'ids': [],
'company': self.start.company.id,
'sale_date': self.start.sale_date,
2023-06-29 15:20:32 +02:00
'end_date': self.start.end_date,
2023-04-20 21:39:06 +02:00
'shop': self.start.shop.id,
'early_morning_included': self.start.early_morning_included,
}
return action, report_context
def transition_print_(self):
return 'end'
class ShopDailyCategoryReport(Report):
'Shop Daily categories'
__name__ = 'sale_pos.shop_daily_category_report'
@classmethod
def get_query(cls, data, products_exception):
pool = Pool()
Sale = pool.get('sale.sale')
Line = pool.get('sale.line')
Invoice = pool.get('account.invoice')
2023-09-19 23:44:43 +02:00
fixed_hour = time(6, 0)
2023-04-20 21:39:06 +02:00
cursor = Transaction().connection.cursor()
sale = Sale.__table__()
line = Line.__table__()
result_ = {}
where_ = sale.state.in_(['processing', 'done'])
where_ = line.product.in_(products_exception)
where_ &= sale.company == data['company']
2023-07-07 00:09:19 +02:00
# where_ &= sale.invoice_type == 'P'
2023-04-20 21:39:06 +02:00
where_ &= sale.number != Null
if data['shop']:
where_ &= sale.shop == data['shop']
if not data['early_morning_included']:
where_ &= sale.invoice_date == data['sale_date']
else:
# Select sales including early morning of next day
_start_date = datetime.combine(data['sale_date'], fixed_hour)
_start_date = Company.convert_timezone(_start_date, True)
2023-06-28 17:40:27 +02:00
end_date = data['sale_date'] + timedelta(days=1) if not data['sale_date'] else data['sale_date'] + timedelta(days=1)
2023-04-20 21:39:06 +02:00
_end_date = datetime.combine(end_date, fixed_hour)
_end_date = Company.convert_timezone(_end_date, True)
where_ &= sale_date >= data['sale_date']
where_ &= sale_date <= end_date
where_ &= create_date >= _start_date
where_ &= create_date <= _end_date
columns_ = [sale.id, Sum(line.unit_price*line.quantity).as_('amount')]
query = line.join(sale, condition=line.sale==sale.id).select(*columns_,
where=where_,
group_by=sale.id)
cursor.execute(*query)
result = cursor.fetchall()
for row in result:
result_[row[0]] = row[1]
return result_
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Sale = pool.get('sale.sale')
Company = pool.get('company.company')
company = Company(data['company'])
Shop = pool.get('sale.shop')
fixed_hour = time(6, 0)
2023-09-19 23:44:43 +02:00
# config = pool.get('sale.configuration')(1)
2023-04-20 21:39:06 +02:00
products_exception = []
amount_exception = {}
if products_exception:
amount_exception = cls.get_query(data, products_exception)
dom_sales = [
('shop', '=', data['shop']),
('company', '=', data['company']),
('number', '!=', None),
2023-07-07 00:17:24 +02:00
# ('invoice_type', '=', 'P'),
2023-04-20 21:39:06 +02:00
]
if not data['early_morning_included']:
2023-06-28 17:40:27 +02:00
if data['end_date']:
dom_sales.append(('sale_date', '>=', data['sale_date']))
dom_sales.append(('sale_date', '<=', data['end_date']))
else:
dom_sales.append(('sale_date', '=', data['sale_date']))
2023-04-20 21:39:06 +02:00
else:
# Select sales including early morning of next day
_start_date = datetime.combine(data['sale_date'], fixed_hour)
_start_date = Company.convert_timezone(_start_date, True)
2023-06-28 17:40:27 +02:00
end_date = data['sale_date'] + timedelta(days=1) if not data['end_date'] else data['end_date'] + timedelta(days=1)
2023-04-20 21:39:06 +02:00
_end_date = datetime.combine(end_date, fixed_hour)
_end_date = Company.convert_timezone(_end_date, True)
dom_sales.append(('sale_date', '>=', data['sale_date']))
dom_sales.append(('sale_date', '<=', end_date))
dom_sales.append(('create_date', '>=', _start_date))
dom_sales.append(('create_date', '<=', _end_date))
2023-06-28 17:40:27 +02:00
print(dom_sales)
2023-04-20 21:39:06 +02:00
states_sale = ['processing', 'done']
dom_sales.append(('state', 'in', states_sale))
sales = Sale.search(dom_sales, order=[('number', 'ASC')])
categories = {}
total_payments = []
2023-09-19 23:44:43 +02:00
print('voy a entrar al for sale')
2023-04-20 21:39:06 +02:00
for sale in sales:
device_id = None
if sale.sale_device:
device_id = sale.sale_device.id
if sale.total_amount <= 0:
continue
if not sale.invoices:
continue
invoice = sale.invoices[0]
if not invoice.number or invoice.total_amount <= 0 or not device_id:
continue
2023-04-21 22:50:16 +02:00
for line in sale.lines:
2023-04-20 21:39:06 +02:00
category_id = '0'
2023-09-19 23:44:43 +02:00
product_id = line.product.id
product_name = line.product.name
line_quantity = line.quantity
line_amount_w_tax = line.amount_w_tax
if product_id in products_exception:
2023-04-20 21:39:06 +02:00
continue
if line.product.categories:
category = line.product.categories[0]
category_id = category.id
2023-09-19 23:44:43 +02:00
try:
if category_id != '0':
categories[category_id]['base'].append(line.amount)
try:
categories[category_id]['products'][product_id]['quantity'] += line_quantity
categories[category_id]['products'][product_id]['amount'] += line_amount_w_tax
total_payments.append(line_amount_w_tax)
except KeyError:
categories[category_id]['products'][product_id] = {
'name': product_name,
'quantity': line_quantity,
'amount': line_amount_w_tax,
}
total_payments.append(line_amount_w_tax)
except KeyError:
2023-04-20 21:39:06 +02:00
categories[category_id] = {
'name': category.name,
'base': [line.amount],
2023-09-19 23:44:43 +02:00
'products': {product_id: {
'name': product_name,
'quantity': line_quantity,
'amount': line_amount_w_tax,
2023-04-20 21:39:06 +02:00
}
}
}
2023-09-19 23:44:43 +02:00
total_payments.append(line_amount_w_tax)
2023-04-20 21:39:06 +02:00
report_context['date'] = data['sale_date']
2023-06-28 17:40:27 +02:00
report_context['end_date'] = data['end_date'] if data['end_date'] else data['sale_date']
2023-04-20 21:39:06 +02:00
report_context['company'] = company.party
report_context['shop'] = Shop(data['shop']).name
report_context['categories'] = categories.values()
report_context['total_payments'] = sum(total_payments)
return report_context