trytonpsk-sale_pos/sale.py

2193 lines
82 KiB
Python
Raw 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.
2020-12-20 20:57:25 +01:00
import math
2022-04-01 01:05:58 +02:00
import calendar
2020-04-15 21:47:31 +02:00
from decimal import Decimal
2022-01-12 16:00:57 +01:00
from datetime import datetime, date, timedelta
2020-04-15 21:47:31 +02:00
from itertools import chain
2022-02-12 17:57:11 +01:00
from sql import Null, Table, With
2022-02-04 18:07:58 +01:00
from sql.operators import NotIn, Or
2022-01-15 00:00:16 +01:00
from sql.aggregate import Sum, Count
2022-08-01 23:13:07 +02:00
from sql.conditionals import Case, Coalesce
2022-01-15 00:00:16 +01:00
2020-04-15 21:47:31 +02:00
from trytond.model import ModelView, fields
from trytond.pool import PoolMeta, Pool
from trytond.transaction import Transaction
2021-02-09 17:17:01 +01:00
from trytond.pyson import Bool, Eval, Not
2020-04-15 21:47:31 +02:00
from trytond.wizard import (
2020-12-26 15:12:46 +01:00
Wizard, StateView, StateAction, StateReport, StateTransition, Button
)
2020-04-15 21:47:31 +02:00
from trytond.report import Report
2021-06-22 20:38:42 +02:00
from trytond.i18n import gettext
from .exceptions import (
ProductMissingTaxError, ImportSalesError, SaleDeleteError,
SaleForceDraftError, SaleDeviceError, DraftStatementError,
PartyMissingAccount
)
2021-06-22 20:38:42 +02:00
from trytond.modules.sale.exceptions import SaleValidationError
2020-04-15 21:47:31 +02:00
_ZERO = Decimal('0.00')
TODAY = date.today()
STATES = {
'readonly': Eval('state').in_(['processing', 'done', 'cancel']),
}
class Sale(metaclass=PoolMeta):
__name__ = 'sale.sale'
self_pick_up = fields.Boolean('Self Pick Up', states=STATES, depends=['state'],
help='The goods are picked up by the customer before the sale, so no '
'shipment is created.')
pos_create_date = fields.DateTime('Create Date', readonly=True)
invoice_number = fields.Char('Invoice Number')
invoice_date = fields.Date('Invoice Date')
invoice = fields.Many2One('account.invoice', 'Invoice')
2022-01-29 16:17:47 +01:00
# Migrated to sale_shop
# payments = fields.One2Many('account.statement.line', 'sale', 'Payments')
# paid_amount = fields.Function(fields.Numeric('Paid Amount', digits=(16, 2)),
# 'get_paid_amount')
# residual_amount = fields.Function(fields.Numeric('Residual Amount',
# digits=(16, 2), readonly=True), 'get_residual_amount')
2020-04-15 21:47:31 +02:00
sale_device = fields.Many2One('sale.device', 'Sale Device',
2021-02-24 04:04:13 +01:00
domain=[('shop', '=', Eval('shop'))], depends=['shop'], states=STATES)
2020-04-15 21:47:31 +02:00
position = fields.Char('Position', states=STATES)
pre_sale = fields.Boolean('Pre-Sale', help="This option for pre-sale, change method of invoice to shipment")
shipment_date = fields.Date('Shipment Date', states=STATES)
2021-01-04 14:11:58 +01:00
turn = fields.Integer('Turn', states=STATES)
2022-06-14 17:38:51 +02:00
reservation= fields.Boolean('Reservation')
2020-04-15 21:47:31 +02:00
@classmethod
def __setup__(cls):
super(Sale, cls).__setup__()
cls.party.states['readonly'] = Bool(Eval('invoice_number'))
cls.state_string = super(Sale, cls).state.translated('state')
2021-02-23 18:40:48 +01:00
for fname in cls.self_pick_up.on_change:
if fname not in cls.shop.on_change:
cls.shop.on_change.add(fname)
if fname not in cls.party.on_change:
cls.party.on_change.add(fname)
2020-04-15 21:47:31 +02:00
cls._buttons.update({
'wizard_generate_invoice': {
'invisible': Eval('state').in_(['done', 'processing', 'cancel']),
'readonly': Not(Bool(Eval('lines'))),
},
'wizard_generate_shipment': {
'invisible': Eval('shipment_state').in_(['sent', 'exception']),
'readonly': Not(Bool(Eval('lines'))),
},
})
@classmethod
def search_rec_name(cls, name, clause):
_, operator, value = clause
if operator.startswith('!') or operator.startswith('not '):
bool_op = 'AND'
else:
bool_op = 'OR'
domain = [
bool_op,
('number', operator, value),
('reference', operator, value),
('description', operator, value),
('invoice.number', operator, value),
]
return domain
2021-09-16 19:27:21 +02:00
# @staticmethod
# def default_sale_device():
# User = Pool().get('res.user')
# user = User(Transaction().user)
# return user.sale_device and user.sale_device.id or None
2020-04-15 21:47:31 +02:00
@classmethod
def process(cls, sales):
2022-09-07 15:56:12 +02:00
configuration = Pool().get('sale.configuration')(1)
2020-04-15 21:47:31 +02:00
for sale in sales:
2021-09-14 00:50:25 +02:00
if sale.invoices:
invoice = sale.invoices[0]
if invoice.state in ('posted', 'paid'):
continue
2021-09-13 19:09:38 +02:00
# cls.recheck_taxes(sale)
2022-09-12 16:06:25 +02:00
if hasattr(configuration, 'password_force_assign') and configuration.password_force_assign and sale.shipment_state == 'none':
2022-09-05 23:58:15 +02:00
cls.validate_stock(sale)
2020-04-15 21:47:31 +02:00
cls.process_pos(sale)
super(Sale, cls).process(sales)
2022-09-05 23:58:15 +02:00
@classmethod
def validate_stock(cls, sale):
Product = Pool().get('product.product')
2022-09-06 00:21:17 +02:00
product_ids = {l.product.id: l.quantity for l in sale.lines}
2022-09-05 23:58:15 +02:00
today = date.today()
with Transaction().set_context({'stock_date_end': today, 'locations': [sale.warehouse.id]}):
products = Product.search([
2022-09-06 00:21:17 +02:00
('id', 'in', product_ids.keys()),
2022-09-05 23:58:15 +02:00
])
for product in products:
2022-09-06 00:21:17 +02:00
if product.quantity <= product_ids[product.id]:
2022-09-05 23:58:15 +02:00
raise SaleValidationError(gettext('sale_pos.msg_product_quantity', s=product.rec_name))
2021-09-13 19:09:38 +02:00
# @classmethod
# def recheck_taxes(cls, sale):
# for line in sale.lines:
# vat_required = None
# if line.product and line.product.account_category:
# for txr in line.product.account_category.customer_taxes_used:
# if txr.type == 'percentage' and txr.rate > 0:
# vat_required = txr.id
# break
# if vat_required:
# tax_obj = [t.id for t in line.taxes if t.rate and t.rate > 0]
# if vat_required not in tax_obj:
# raise ProductMissingTaxError(
# gettext('sale_pos.msg_missing_tax', s=line.product.rec_name))
2021-01-14 01:21:41 +01:00
2020-12-09 04:53:04 +01:00
def get_tax_amount(self):
# Esto es necesario para impuestos de Licores y Cigarrillos
values = self._get_taxes().values()
res = sum((v['amount'] for v in values), Decimal(0))
Tax = Pool().get('account.tax')
taxes_update = Tax.search([
('type', '=', 'fixed'),
('group.kind', '=', 'sale'),
('amount', '=', 0),
])
taxes_update_ids = [t.id for t in taxes_update]
taxes_update_id = None
if taxes_update_ids:
taxes_update_id = taxes_update_ids[0]
amounts = []
if taxes_update_id:
for l in self.lines:
2020-12-10 14:37:54 +01:00
if not l.product or (not hasattr(l.product, 'extra_tax') or not l.product.extra_tax):
2020-12-09 04:53:04 +01:00
continue
2021-01-13 18:29:40 +01:00
raw_val = Decimal(float(l.product.extra_tax) * l.quantity)
val = self.currency.round(raw_val)
2020-12-09 04:53:04 +01:00
amounts.append(val)
return res + sum(amounts)
2021-12-01 17:38:31 +01:00
# @classmethod
# def import_data(cls, fields_names, data):
# pool = Pool()
# Product = pool.get('product.product')
# Party = pool.get('party.party')
# Invoice = pool.get('account.invoice')
# SaleLine = pool.get('sale.line')
# Voucher = pool.get('account.voucher')
# PaymentMode = pool.get('account.voucher.paymode')
# Tax = pool.get('account.tax')
# user_ = pool.get('res.user')(Transaction().user)
# shop_id = user_.shop.id
# device_id = user_.sale_device.id
# count = 0
#
# # number_sales = list(set([v[0] for v in data[1:]]))
# code_products = list(set([v[6] for v in data[1:]]))
# number_parties = list(set([v[4] for v in data[1:]]))
#
# products = Product.search([
# ('code', 'in', code_products),
# ('salable', '=', 'true')
# ])
# products = [p.code for p in products]
# not_product = [code for code in code_products if code not in products]
# if not products or len(not_product) > 0:
# not_product = code_products if not products else not_product
# not_product = ', '.join(map(str, not_product))
# raise ImportSalesError(
# gettext('sale_pos.msg_import_data_sale', field='producto', s=not_product))
#
# parties = Party.search([
# ('id_number', 'in', number_parties),
# ])
# parties = [p.id_number for p in parties]
# not_party = [party for party in number_parties if party not in parties]
# if not parties or len(not_party) > 0:
# not_party = number_parties if not parties else not_party
# not_party = ', '.join(map(str, not_party))
# raise ImportSalesError(
# gettext('sale_pos.msg_import_data_sale', field='tercero', s=not_party))
#
# sale_to_create = {}
# sales_to_pay = []
# for row in data[1:]:
# code_ = row[6]
# products = Product.search([
# ('code', '=', code_)
# ])
# product = products[0]
# day, month, year = row[3].split('/')
# sale_date = date(int(year), int(month), int(day))
# partys = Party.search([
# ('id_number', '=', row[4])
# ])
# party = partys[0]
# if row[0] not in sale_to_create.keys():
# # with Transaction().set_context(ctx):
# sale, = cls.create([{
# 'sale_date': sale_date,
# 'party': party.id,
# 'number': row[0],
# 'invoice_number': row[0],
# 'invoice_date': sale_date,
# 'invoice_type': 'P',
# 'description': row[1],
# 'reference': row[2],
# 'payment_term': 1,
# 'shop': shop_id,
# 'sale_device': device_id,
# 'invoice_address': party.address_get(type='invoice'),
# 'shipment_address': party.address_get(type='delivery'),
# }])
# sale.on_change_party()
# sale.save()
# sale_to_create[row[0]] = sale.id
# payment_modes = PaymentMode.search([
# ('id', '=', row[10])
# ])
# if not payment_modes:
# not_party
# raise ImportSalesError(
# gettext('sale_pos.msg_import_data_sale', field='modo de pago', s=row[10]))
# sales_to_pay.append({
# 'sale': sale,
# 'payment_mode': payment_modes[0]
# })
# count += 1
# sale_id = sale_to_create[row[0]]
# tax_imp = list(product.customer_taxes_used)
# if row[9]:
# tax = Tax.search(['id', '=', row[9]])
# tax_imp.extend(tax)
# line = {
# 'sale': sale_id,
# 'product': product.id,
# 'quantity': row[7],
# 'description': row[5],
# 'unit_digits': product.sale_uom.digits,
# 'unit': product.sale_uom,
# 'unit_price': Decimal(row[8]),
# 'discount': Decimal('0.00'),
# 'taxes': [('add', tax_imp)],
# }
# SaleLine.create([line])
#
# for p in sales_to_pay:
# sale = p['sale']
# payment_mode = p['payment_mode']
# cls.store_cache([sale])
# sale = cls.process_pos(sale)
# invoice = sale.invoice
# invoice.accounting_date = sale.invoice_date
# cls.post_invoices(sale)
# sale.state = 'done'
# sale.invoice_state = 'paid'
# sale.save()
# vouchers = Invoice.create_voucher([invoice])
# for voucher in vouchers:
# voucher.date = sale.invoice_date
# voucher.payment_mode = payment_mode
# voucher.save()
# Voucher.process([voucher])
# Voucher.post([voucher])
#
# return count
2021-03-31 21:33:38 +02:00
2020-12-20 20:57:25 +01:00
def create_invoice(self):
'Create and return an invoice'
pool = Pool()
Invoice = pool.get('account.invoice')
if self.invoice_method == 'manual':
return
invoice_lines = []
sales = [self]
for sale in sales:
for line in sale.lines:
if self.total_amount < 0 and line.quantity > 0:
continue
if self.total_amount > 0 and line.quantity < 0:
continue
invoice_lines.append(line.get_invoice_line())
invoice_lines = list(chain(*invoice_lines))
if not invoice_lines:
return
2021-01-13 14:16:24 +01:00
sale = sales[0]
2020-12-20 20:57:25 +01:00
invoice = self._get_invoice_sale()
2021-01-13 14:16:24 +01:00
if self.invoice_type:
invoice.authorization = self._get_authorization(sale)
invoice.invoice_type = self.invoice_type
2020-12-20 20:57:25 +01:00
if getattr(invoice, 'lines', None):
invoice_lines = list(invoice.lines) + invoice_lines
invoice.lines = invoice_lines
2021-01-14 01:21:41 +01:00
invoice.turn = self._get_turn()
2020-12-20 20:57:25 +01:00
invoice.save()
Invoice.update_taxes([invoice])
return invoice
2021-01-13 14:16:24 +01:00
def _get_authorization(self, sale):
authorization_id = None
if sale.untaxed_amount_cache >= 0:
2021-01-13 14:16:24 +01:00
if sale.invoice_type == 'P' and sale.shop.pos_authorization:
authorization_id = sale.shop.pos_authorization.id
elif sale.invoice_type == 'M' and sale.shop.manual_authorization:
authorization_id = sale.shop.manual_authorization.id
2021-01-13 18:53:05 +01:00
elif sale.invoice_type == 'C' and sale.shop.computer_authorization:
authorization_id = sale.shop.computer_authorization.id
2021-01-13 14:16:24 +01:00
elif sale.invoice_type in ['1', '2', '3'] and sale.shop.electronic_authorization:
authorization_id = sale.shop.electronic_authorization.id
elif sale.shop.debit_note_electronic_authorization and sale.invoice_type == '92':
authorization_id = sale.shop.debit_note_electronic_authorization.id
else:
if sale.shop.credit_note_electronic_authorization and sale.invoice_type in ['91', 'N']:
authorization_id = sale.shop.credit_note_electronic_authorization.id
return authorization_id
2020-04-15 21:47:31 +02:00
@classmethod
def process_pos(cls, sale):
2021-09-20 18:51:23 +02:00
if not sale:
return
2021-09-14 00:50:25 +02:00
if sale.invoices:
invoice = sale.invoices[0]
if invoice.number and invoice.state != 'draft':
2021-09-20 18:51:23 +02:00
return sale
2020-04-15 21:47:31 +02:00
pool = Pool()
Date = pool.get('ir.date')
# We need to keep that sequence for invoices been taked from shop
# configuration instead fiscalyear, because some countries sequences
# are setted by shop
number = None
invoice = sale.create_invoice()
sale.set_invoice_state()
2021-07-21 19:33:39 +02:00
sequence = sale.get_sequence(sale)
2020-04-15 21:47:31 +02:00
if not sale.invoice_number and sale.invoice_method == 'order':
2021-08-07 18:06:56 +02:00
if sequence:
2021-07-21 19:33:39 +02:00
number = sequence.get()
2020-04-15 21:47:31 +02:00
sale_date = Date.today()
cls.write([sale], {
'invoice_number': number,
'invoice_date': sale_date,
})
else:
number = sale.invoice_number
position = sale.position if sale.position else None
2022-02-07 21:09:56 +01:00
sale_kind = None
if hasattr(sale, 'kind') and sale.kind:
sale_kind = sale.kind
2020-04-15 21:47:31 +02:00
if invoice:
if sale.invoice_date:
inv_date = sale.invoice_date
2021-04-06 14:46:38 +02:00
elif sale.shipment_date:
inv_date = sale.shipment_date
2020-04-15 21:47:31 +02:00
else:
inv_date = Date.today()
sale.invoice = invoice.id
2020-12-20 20:57:25 +01:00
to_write = {
2020-04-15 21:47:31 +02:00
'shop': sale.shop.id,
'invoice_date': inv_date,
'number': number,
'reference': sale.reference or sale.number,
'position': position,
2021-01-04 14:11:58 +01:00
'turn': sale.turn,
2020-12-20 20:57:25 +01:00
}
2022-02-07 18:50:54 +01:00
if sale_kind:
to_write['sale_kind'] = sale_kind
2020-04-15 21:47:31 +02:00
if sale.invoice_type:
2021-01-13 14:16:24 +01:00
pass
2020-12-20 20:57:25 +01:00
invoice.write([invoice], to_write)
2020-04-15 21:47:31 +02:00
sale.save()
return sale
@classmethod
def cancel(cls, sales):
pool = Pool()
Invoice = pool.get('account.invoice')
Journal = pool.get('account.journal')
super(Sale, cls).cancel(sales)
journals = Journal.search([
('type', '=', 'revenue'),
])
if journals:
journal = journals[0]
else:
return
for sale in sales:
if not sale.number or not sale.invoice_number:
continue
sale_invoices = list(sale.invoices)
if not sale.invoices:
invoice, = Invoice.create([{
'party': sale.party.id,
'account': sale.party.account_receivable.id,
'invoice_date': sale.invoice_date or sale.sale_date,
'payment_term': sale.payment_term.id,
'salesman': sale.salesman and sale.salesman.id,
'journal': journal.id,
'invoice_address': sale.invoice_address.id,
'number': sale.invoice_number,
'reference': sale.number
}])
sale_invoices.append(invoice)
Invoice.cancel(sale_invoices)
@staticmethod
def default_party():
User = Pool().get('res.user')
user = User(Transaction().user)
return user.shop.party.id if user.shop and user.shop.party else None
2021-02-09 17:17:01 +01:00
@fields.depends('invoice_method', 'pre_sale')
2020-04-15 21:47:31 +02:00
def on_change_pre_sale(self):
2021-01-04 14:11:58 +01:00
if self.pre_sale:
2020-04-15 21:47:31 +02:00
self.invoice_method = 'shipment'
else:
self.invoice_method = 'order'
@classmethod
def create(cls, vlist):
now = datetime.now()
vlist = [x.copy() for x in vlist]
for vals in vlist:
vals['pos_create_date'] = now
return super(Sale, cls).create(vlist)
@classmethod
def delete(cls, sales):
for sale in sales:
if sale.invoice_number:
2021-06-22 20:38:42 +02:00
raise SaleDeleteError(
gettext('sale_pos.msg_delete_invoice_number', sale=sale.rec_name, s=sale.invoice_number))
2020-04-15 21:47:31 +02:00
super(Sale, cls).delete(sales)
@classmethod
@ModelView.button_action('sale_pos.wizard_add_product')
def wizard_add_product(cls, sales):
pass
@classmethod
def process_sale_pos(cls, sale):
# We must set directly state and amounts cache because is faster
2021-02-20 16:25:06 +01:00
# 'state': 'confirmed',
2020-04-15 21:47:31 +02:00
cls.write([sale], {
2021-02-20 16:25:06 +01:00
'state': 'processing',
2020-04-15 21:47:31 +02:00
'untaxed_amount_cache': sale.untaxed_amount,
'tax_amount_cache': sale.tax_amount,
'total_amount_cache': sale.total_amount
})
sale = cls.process_pos(sale)
return sale
@classmethod
def update_state(cls, sales):
for sale in sales:
if not sale.is_done():
continue
@classmethod
def do_stock_moves(cls, sales):
for sale in sales:
2021-05-18 17:27:56 +02:00
if sale.shipment_state == "none":
sale.create_shipment('out')
sale.set_shipment_state()
2020-04-15 21:47:31 +02:00
@classmethod
def post_invoices(cls, sale):
pool = Pool()
Date = pool.get('ir.date')
Invoice = pool.get('account.invoice')
invoice = None
if sale.invoice:
invoice = sale.invoice
else:
if sale.invoices:
invoice = sale.invoices[0]
if invoice:
2020-04-24 15:45:22 +02:00
if invoice.payment_term.id != sale.payment_term.id:
invoice.payment_term = sale.payment_term
2020-04-15 21:47:31 +02:00
_invoice_date = sale.invoice_date or Date.today()
if invoice.state == 'draft':
if not getattr(invoice, 'invoice_date', False):
invoice.invoice_date = _invoice_date
if not getattr(invoice, 'accounting_date', False):
invoice.accounting_date = _invoice_date or date.today()
2022-06-01 17:20:51 +02:00
invoice.save()
if hasattr(sale.shop, 'workflow_invoice') \
and sale.shop.workflow_invoice == 'validated':
Invoice.validate_invoice([invoice])
return
Invoice.process_invoice([invoice])
2022-06-14 17:38:51 +02:00
if invoice.state == 'posted' and sale.residual_amount <= 0:
try:
cls.do_reconcile([sale])
except:
pass
2020-04-15 21:47:31 +02:00
@classmethod
def do_reconcile(cls, sales):
2022-06-14 17:38:51 +02:00
print('ingresa to reconcile')
2020-04-15 21:47:31 +02:00
Reconciliation = Pool().get('account.move.reconciliation')
2022-06-14 17:38:51 +02:00
Config = Pool().get('sale.configuration')
account_advance = Config(1).advance_account.id if Config(1).advance_account else None
2020-04-15 21:47:31 +02:00
for sale in sales:
reconcile_lines = []
2022-06-14 17:38:51 +02:00
advance_lines = []
2020-04-15 21:47:31 +02:00
account_reconcile_id = None
invoice_id = None
if not sale.payments or not sale.number:
continue
try:
2022-06-14 17:38:51 +02:00
# if 1:
2020-04-15 21:47:31 +02:00
for invoice in sale.invoices:
2022-06-14 17:38:51 +02:00
print('ingresa a invoice')
2020-04-15 21:47:31 +02:00
if invoice.state == 'paid' or not invoice.move:
continue
2022-08-19 18:23:55 +02:00
invoice.process([invoice])
2020-04-15 21:47:31 +02:00
invoice_id = invoice.id
2022-06-14 17:38:51 +02:00
invoice_ = invoice
2020-04-15 21:47:31 +02:00
account_reconcile_id = invoice.account.id
for line in invoice.payment_lines:
if not line.reconciliation and line.account.id == account_reconcile_id:
2022-06-14 17:38:51 +02:00
reconcile_lines.append(line)
2020-04-15 21:47:31 +02:00
for l in invoice.move.lines:
if l.account.id == account_reconcile_id:
2022-06-14 17:38:51 +02:00
reconcile_lines.append(l)
2020-04-15 21:47:31 +02:00
break
for st_line in sale.payments:
2022-08-20 17:27:16 +02:00
if st_line.account.id == invoice_.account.id:
2022-06-14 17:38:51 +02:00
st_line.invoice = invoice_id
st_line.save()
elif st_line.move and st_line.move.state != 'posted':
st_line.move.post([st_line.move])
2020-04-15 21:47:31 +02:00
if not st_line.move:
st_line.create_move()
2022-06-14 17:38:51 +02:00
2020-04-15 21:47:31 +02:00
for ml in st_line.move.lines:
if not ml.reconciliation and ml.account.id == account_reconcile_id:
2022-06-14 17:38:51 +02:00
reconcile_lines.append(ml)
if account_advance and not ml.reconciliation and ml.account.id == account_advance:
advance_lines.append(ml)
if advance_lines:
invoice_.create_cross_advance(advance_lines)
amount_reconcile = sum(l.debit-l.credit for l in reconcile_lines)
if reconcile_lines and amount_reconcile == 0:
2020-04-15 21:47:31 +02:00
Reconciliation.create([{
'lines': [('add', reconcile_lines)],
'date': TODAY,
}])
2020-12-20 20:57:25 +01:00
sale.write([sale], {'state': 'done'})
2020-04-15 21:47:31 +02:00
except Exception:
2022-06-14 17:38:51 +02:00
# else:
2020-04-15 21:47:31 +02:00
print('Warning: Sale number not processed %s' % sale.number)
@classmethod
def workflow_to_end(cls, sales):
2021-09-18 22:26:15 +02:00
sale = sales[0]
_sale = cls.process_sale_pos(sale)
if _sale:
sale = _sale
2022-06-01 17:20:51 +02:00
cls.post_invoices(sale)
2021-09-18 22:26:15 +02:00
cls.do_stock_moves([sale])
cls.do_reconcile([sale])
cls.update_state([sale])
2020-04-15 21:47:31 +02:00
@classmethod
@ModelView.button
def wizard_generate_invoice(cls, sales):
cls.quote(sales)
cls.workflow_to_end(sales)
@classmethod
@ModelView.button
def wizard_generate_shipment(cls, sales):
cls.do_stock_moves(sales)
@classmethod
def copy(cls, sales, default=None):
if default is None:
default = {}
default['invoice'] = None
default['invoice_number'] = None
default['invoice_date'] = None
if sales:
sale = sales[0]
if sale.invoice and sale.invoice.number:
default['reference'] = sale.invoice.number
default['invoice_number'] = None
return super(Sale, cls).copy(sales, default)
def get_sequence(self, sale):
2021-07-21 19:33:39 +02:00
sequence = None
if sale.untaxed_amount_cache >= 0:
2020-04-15 21:47:31 +02:00
if sale.invoice_type == 'C' and sale.shop.computer_authorization:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.computer_authorization.sequence
2020-04-15 21:47:31 +02:00
elif sale.invoice_type == 'P' and sale.shop.pos_authorization:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.pos_authorization.sequence
2020-04-15 21:47:31 +02:00
elif sale.invoice_type == 'M' and sale.shop.manual_authorization:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.manual_authorization.sequence
2020-04-15 21:47:31 +02:00
elif sale.invoice_type in ['1','2','3'] and sale.shop.electronic_authorization:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.electronic_authorization.sequence
2020-04-15 21:47:31 +02:00
elif sale.shop.invoice_sequence:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.invoice_sequence
2020-04-15 21:47:31 +02:00
else:
if sale.shop.credit_note_electronic_authorization and sale.invoice_type in ['91', 'N']:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.credit_note_electronic_authorization.sequence
2020-04-15 21:47:31 +02:00
elif sale.shop.debit_note_electronic_authorization and sale.invoice_type == '92':
2021-07-21 19:33:39 +02:00
sequence = sale.shop.debit_note_electronic_authorization.sequence
2020-04-15 21:47:31 +02:00
else:
if sale.shop.credit_note_sequence:
2021-07-21 19:33:39 +02:00
sequence = sale.shop.credit_note_sequence
return sequence
2020-04-15 21:47:31 +02:00
def create_shipment(self, shipment_type):
if self.self_pick_up:
return self.create_moves_without_shipment(shipment_type)
return super(Sale, self).create_shipment(shipment_type)
def create_moves_without_shipment(self, shipment_type):
pool = Pool()
Move = pool.get('stock.move')
if self.shipment_method != 'order':
return
moves = {}
for line in self.lines:
move = line.get_move(shipment_type)
if move:
moves[line.id] = move
to_create = []
for m in moves:
2021-02-09 17:17:01 +01:00
moves[m].state = 'draft'
2020-04-15 21:47:31 +02:00
to_create.append(moves[m]._save_values)
Move.create(to_create)
Move.do(self.moves)
self.set_shipment_state()
2021-02-09 17:17:01 +01:00
# WTF
# @fields.depends('lines', 'currency', 'party')
# def on_change_lines(self):
# '''
# Overrides this method completely if the sale is self pick up to improve
# performance: Computes untaxed, total and tax amounts from the already
# computed values in sale lines.
# '''
#
# self.untaxed_amount = Decimal('0.0')
# self.tax_amount = Decimal('0.0')
# self.total_amount = Decimal('0.0')
#
# if self.lines:
# self.untaxed_amount = reduce(lambda x, y: x + y,
# [(getattr(l, 'amount', None) or Decimal(0))
# for l in self.lines if l.type == 'line'], Decimal(0)
# )
# self.total_amount = reduce(lambda x, y: x + y,
# [(getattr(l, 'amount_w_tax', None) or Decimal(0))
# for l in self.lines if l.type == 'line'], Decimal(0)
# )
# if self.currency:
# self.untaxed_amount = self.currency.round(self.untaxed_amount)
# self.total_amount = self.currency.round(self.total_amount)
# self.tax_amount = self.total_amount - self.untaxed_amount
# if self.currency:
# self.tax_amount = self.currency.round(self.tax_amount)
2020-04-15 21:47:31 +02:00
def get_invoice_number(self, name=None):
if self.invoices:
return self.invoices[0].number
@classmethod
def dash_on_change_party(cls, args, ctx={}):
if args.get('party'):
Party = Pool().get('party.party')
party = Party(args.get('party')['id'])
address = party.address_get(type='invoice')
return {
'invoice_address': {'id': address.id, 'name': address.name},
'shipment_address': None
}
2021-02-09 17:17:01 +01:00
def _get_turn(self):
Statement = Pool().get('account.statement')
if not self.sale_device:
return
statements = Statement.search([
('state', '=', 'draft'),
('sale_device', '=', self.sale_device.id),
('turn', '!=', None),
2022-10-14 00:32:56 +02:00
], order=[('create_date', 'DESC')])
2021-02-09 17:17:01 +01:00
if statements:
return statements[0].turn
2020-04-15 21:47:31 +02:00
class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line'
2021-02-09 17:17:01 +01:00
# @fields.depends('unit_price', 'unit_price_full', 'product', 'quantity')
# def on_change_unit_price_full(self, name=None):
# pool = Pool()
# Tax = pool.get('account.tax')
# if self.product and self.unit_price_full and self.product.template.customer_taxes_used:
# res = Tax.reverse_compute(self.unit_price_full,
# self.product.template.customer_taxes_used)
# self.unit_price = res
2020-04-15 21:47:31 +02:00
@classmethod
def dash_on_change_line(cls, args, ctx):
if not args.get('quantity') or not args.get('product'):
return {}
Line = Pool().get('sale.line')
Sale = Pool().get('sale.sale')
Product = Pool().get('product.product')
PriceListLine = Pool().get('product.price_list.line')
product_id = args['product']['id']
product = Product(product_id)
company_id = ctx.get('company')
with Transaction().set_context(ctx):
unit_price = product.list_price
if args.get('quantity'):
quantity = int(args.get('quantity'))
else:
quantity = 1
if ctx.get('price_list'):
price_list_id = ctx.get('price_list')['id']
else:
price_list_id = None
percent_commission = 0
if price_list_id:
price_lines = PriceListLine.search([
('price_list', '=', price_list_id),
('product', '=', product_id),
])
if price_lines:
price_line = price_lines[0]
unit_price = float(unit_price)
unit_price = Decimal(eval(price_line.formula))
percent_commission = price_line.price_list.percent_commission
sale = Sale(company=company_id)
taxes_ids = [t.id for t in product.customer_taxes_used]
line = Line(
sale=sale.id,
type='line',
taxes=taxes_ids,
unit_price=unit_price,
quantity=quantity,
product=product.id,
)
res = cls.get_price_with_tax([line], ['amount_w_tax', 'unit_price_w_tax'])
res = {
'unit_price_w_tax': math.ceil(res['unit_price_w_tax'][None]),
'amount_w_tax': math.ceil(res['amount_w_tax'][None]),
'unit_price': math.ceil(unit_price),
'taxes': [[('add'), taxes_ids]],
'unit': product.template.default_uom.id,
'type': 'line',
}
if percent_commission:
res['commission_amount'] = round((((unit_price) * quantity) * percent_commission), 0)
return res
@classmethod
def __setup__(cls):
super(SaleLine, cls).__setup__()
# Allow edit product, quantity and unit in lines without parent sale
for fname in ('product', 'quantity', 'unit'):
field = getattr(cls, fname)
if field.states.get('readonly'):
del field.states['readonly']
@staticmethod
def default_sale():
if Transaction().context.get('sale'):
return Transaction().context.get('sale')
return None
2021-02-09 17:17:01 +01:00
# @fields.depends('sale')
# def on_change_product(self):
# Sale = Pool().get('sale.sale')
#
# if not self.sale:
# sale_id = Transaction().context.get('sale')
# if sale_id:
# self.sale = Sale(sale_id)
# super(SaleLine, self).on_change_product()
2020-04-15 21:47:31 +02:00
@fields.depends('sale')
def on_change_with_amount(self):
if not self.sale:
self.sale = Transaction().context.get('sale')
return super(SaleLine, self).on_change_with_amount()
def get_from_location(self, name):
res = super(SaleLine, self).get_from_location(name)
if self.sale.self_pick_up:
if self.warehouse and self.quantity >= 0:
return self.warehouse.storage_location.id
return res
def get_to_location(self, name):
res = super(SaleLine, self).get_to_location(name)
if self.sale.self_pick_up:
if self.warehouse and self.quantity < 0:
return self.warehouse.storage_location.id
return res
def compute_price_w_tax(self, line):
Tax = Pool().get('account.tax')
res = line.unit_price * Decimal(line.quantity)
2021-11-27 16:18:57 +01:00
if line.taxes and line.unit_price:
tax_list = Tax.compute(line.taxes,
line.unit_price or Decimal('0.0'), 1)
res = sum([t['amount'] for t in tax_list], Decimal('0.0'))
res = (res + line.unit_price) * Decimal(line.quantity)
2021-11-27 16:18:57 +01:00
if line.product.extra_tax:
res += line.product.extra_tax * Decimal(line.quantity)
res = res.quantize(
Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
return res
2020-04-15 21:47:31 +02:00
class SaleForceDraft(Wizard):
'Sale Force Draft'
__name__ = 'sale_pos.force_draft'
start_state = 'force_draft'
force_draft = StateTransition()
@classmethod
def __setup__(cls):
super(SaleForceDraft, cls).__setup__()
def transition_force_draft(self):
sale_table = Table('sale_sale')
invoice_table = Table('account_invoice')
move_table = Table('account_move')
stock_move_table = Table('stock_move')
Sale = Pool().get('sale.sale')
2021-11-19 23:25:59 +01:00
MoveLine = Pool().get('account.move.line')
2020-04-15 21:47:31 +02:00
Date = Pool().get('ir.date')
cursor = Transaction().connection.cursor()
ids = Transaction().context['active_ids']
if not ids:
return 'end'
sales = Sale.browse(ids)
for sale in sales:
# if sale.sale_date != Date.today():
# return 'end'
# The payments must be delete
for pay in sale.payments:
if pay.statement.state != 'draft':
return 'end'
if pay.move:
self.unreconcile_move(pay.move)
2021-09-08 16:49:16 +02:00
pay.invoice = None
pay.save()
2020-04-15 21:47:31 +02:00
pay.move.delete([pay.move])
pay.delete([pay])
# The invoices must be delete
for invoice in sale.invoices:
if (hasattr(invoice, 'cufe') and invoice.cufe) or \
hasattr(invoice, 'electronic_state') and \
invoice.electronic_state == 'submitted':
2021-06-22 20:38:42 +02:00
raise SaleForceDraftError(
gettext('sale_pos.msg_with_electronic_invoice'))
2021-11-19 23:25:59 +01:00
if invoice.move:
move = invoice.move
MoveLine.check_journal_period_modify(move.period, move.journal)
2020-04-15 21:47:31 +02:00
if invoice.state == 'paid':
self.unreconcile_move(invoice.move)
if invoice.move:
cursor.execute(*move_table.update(
columns=[move_table.state],
values=['draft'],
where=move_table.id == invoice.move.id)
)
cursor.execute(*move_table.delete(
where=move_table.id == invoice.move.id)
)
cursor.execute(*invoice_table.update(
columns=[invoice_table.state, invoice_table.number],
values=['validate', None],
where=invoice_table.id == invoice.id)
)
cursor.execute(*invoice_table.delete(
where=invoice_table.id == invoice.id)
)
if sale.id:
cursor.execute(*sale_table.update(
2021-05-18 17:27:56 +02:00
columns=[sale_table.state, sale_table.shipment_state, sale_table.invoice_state],
values=['draft', 'none', 'none'],
2020-04-15 21:47:31 +02:00
where=sale_table.id == sale.id)
)
# The stock moves must be delete
stock_moves = [m.id for line in sale.lines for m in line.moves]
if stock_moves:
cursor.execute(*stock_move_table.update(
columns=[stock_move_table.state],
values=['draft'],
where=stock_move_table.id.in_(stock_moves)
))
cursor.execute(*stock_move_table.delete(
where=stock_move_table.id.in_(stock_moves))
)
return 'end'
def unreconcile_move(self, move):
Reconciliation = Pool().get('account.move.reconciliation')
reconciliations = [l.reconciliation for l in move.lines if l.reconciliation]
if reconciliations:
Reconciliation.delete(reconciliations)
class SaleUpdateDateStart(ModelView):
'Sale Update Date Start'
__name__ = 'sale_pos.sale_update_date.start'
new_date = fields.Date('New Date', required=True)
class SaleUpdateDate(Wizard):
'Sale Update Date'
__name__ = 'sale_pos.sale_update_date'
start = StateView('sale_pos.sale_update_date.start',
'sale_pos.sale_update_date_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'accept', 'tryton-ok', default=True),
])
accept = StateTransition()
def transition_accept(self):
sale = Table('sale_sale')
id_ = Transaction().context['active_id']
cursor = Transaction().connection.cursor()
if id_:
cursor.execute(*sale.update(
columns=[sale.sale_date],
values=[self.start.new_date],
where=sale.id == id_)
)
return 'end'
class SaleDetailedStart(ModelView):
'Sale Detailed Start'
__name__ = 'sale_pos.sale_detailed.start'
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
company = fields.Many2One('company.company',
'Company', required=True)
salesman = fields.Many2One('company.employee', 'Salesman')
party = fields.Many2One('party.party', 'Party')
product = fields.Many2One('product.product', 'Product')
shop = fields.Many2One('sale.shop', 'Shop')
@staticmethod
def default_company():
return Transaction().context.get('company')
class SaleDetailed(Wizard):
'Sale Detailed'
__name__ = 'sale_pos.sale_detailed'
start = StateView('sale_pos.sale_detailed.start',
'sale_pos.sale_detailed_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
2021-02-17 19:38:45 +01:00
])
2020-04-15 21:47:31 +02:00
print_ = StateAction('sale_pos.report_sale_detailed')
@classmethod
def __setup__(cls):
super(SaleDetailed, cls).__setup__()
def do_print_(self, action):
salesman_id = None
party_id = None
product_id = None
shop_id = None
if self.start.salesman:
salesman_id = self.start.salesman.id
if self.start.shop:
shop_id = self.start.shop.id
if self.start.party:
party_id = self.start.party.id
if self.start.product:
product_id = self.start.product.id
data = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'salesman': salesman_id,
'party': party_id,
'product': product_id,
'shop': shop_id,
}
return action, data
def transition_print_(self):
return 'end'
class SaleDetailedReport(Report):
__name__ = 'sale_pos.report_sale_detailed'
@classmethod
2021-06-22 20:38:42 +02:00
def get_context(cls, records, header, data):
2021-09-18 07:12:15 +02:00
from operator import itemgetter
2021-06-22 20:38:42 +02:00
report_context = super().get_context(records, header, data)
2020-04-15 21:47:31 +02:00
pool = Pool()
2021-09-18 07:12:15 +02:00
Invoice = pool.get('account.invoice')
2021-02-17 19:38:45 +01:00
InvoiceLine = pool.get('account.invoice.line')
2020-04-15 21:47:31 +02:00
Company = pool.get('company.company')
2021-09-18 07:12:15 +02:00
Product = pool.get('product.product')
2020-04-15 21:47:31 +02:00
2021-09-18 07:12:15 +02:00
invoice_dom = [
('invoice_date', '>=', data['start_date']),
('invoice_date', '<=', data['end_date']),
('company', '=', data['company']),
('type', '=', 'out'),
('state', 'in', ['posted', 'paid', 'validated']),
2020-04-15 21:47:31 +02:00
]
2021-09-18 07:12:15 +02:00
2020-04-15 21:47:31 +02:00
if data['salesman']:
2021-09-18 07:12:15 +02:00
invoice_dom.append(
('salesman', '=', data['salesman'])
2020-04-15 21:47:31 +02:00
)
if data['shop']:
2021-09-18 07:12:15 +02:00
invoice_dom.append(
('shop', '=', data['shop'])
2020-04-15 21:47:31 +02:00
)
if data['party']:
2021-09-18 07:12:15 +02:00
invoice_dom.append(
('party', '=', data['party'])
2021-02-17 19:38:45 +01:00
)
2020-04-15 21:47:31 +02:00
2021-09-18 07:12:15 +02:00
fields_inv = [
'id', 'number', 'invoice_date', 'state', 'payment_term.name',
2022-02-02 23:24:09 +01:00
'shop.name', 'party.name', 'invoice_type'
2021-09-18 07:12:15 +02:00
]
2021-02-17 19:38:45 +01:00
2021-09-18 07:12:15 +02:00
invoices = Invoice.search_read(invoice_dom, fields_names=fields_inv,
order=[('invoice_date', 'ASC')]
)
line_dom = [
('product', '!=', None),
('type', '=', 'line'),
]
if data['product']:
line_dom.append(('product', '=', data['product']))
invoices_ids = {inv['id']: inv for inv in invoices}
line_dom.append(('invoice', 'in', invoices_ids.keys()))
fields_lines = [
2022-08-20 17:27:16 +02:00
'id', 'product.name', 'product.code', 'unit.symbol', 'quantity', 'invoice',
2021-09-18 07:12:15 +02:00
'product.last_cost', 'product.cost_price', 'unit_price',
'product.account_category.name', 'taxes'
]
2020-04-15 21:47:31 +02:00
2022-02-02 23:24:09 +01:00
config = pool.get('sale.configuration')(1)
products_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 len(products_exception) > 0:
line_dom.append(('product', 'not in', products_exception))
2021-09-18 07:12:15 +02:00
lines = InvoiceLine.search_read(line_dom, fields_names=fields_lines)
untaxed_amount = []
total_amount = []
untaxed_amount_append = untaxed_amount.append
total_amount_append = total_amount.append
get_prices_taxed = Product.get_prices_taxed
2021-09-19 09:02:17 +02:00
dgetter = itemgetter(
'invoice', 'unit_price', 'quantity', 'product.', 'taxes'
)
pt_getter = itemgetter(
'id', 'name', 'cost_price', 'last_cost', 'account_category.'
)
2021-09-18 07:12:15 +02:00
for line in lines:
invoice, unit_price, qty, product, taxes = dgetter(line)
2021-09-19 09:02:17 +02:00
product_id, name, cost_price, last_cost, category = pt_getter(product)
2021-09-18 07:12:15 +02:00
line.update(invoices_ids[invoice])
2021-09-19 09:02:17 +02:00
cost_price = cost_price or last_cost or 0
2021-09-18 07:12:15 +02:00
amount = round(qty * float(unit_price), 2)
utility = unit_price - cost_price
cost_taxed, sale_price_taxed = get_prices_taxed(
product_id, cost_price, unit_price, taxes
)
2022-02-04 22:17:48 +01:00
print(cost_taxed, sale_price_taxed, 'casdf')
2021-09-18 07:12:15 +02:00
amount_taxed = float(sale_price_taxed) * qty
2021-09-19 09:02:17 +02:00
line.update({
'amount': amount,
'cost_price': cost_price,
'product': name,
2022-08-20 17:27:16 +02:00
'code':product['code'],
2021-09-19 09:02:17 +02:00
'amount_taxed': amount_taxed,
'total_cost': float(cost_taxed) * qty,
'utility': float(utility) * qty,
'utility_rate': (utility / cost_price) if cost_price else 0,
'sale_price_taxed': sale_price_taxed,
'cost_price_taxed': cost_taxed,
'category': category['name'],
'shop': line['shop.']['name'] if line.get('shop.') else '',
})
2021-09-18 07:12:15 +02:00
untaxed_amount_append(amount)
total_amount_append(amount_taxed)
report_context['records'] = lines
2021-02-17 19:38:45 +01:00
report_context['untaxed_amount'] = sum(untaxed_amount)
2021-09-18 07:12:15 +02:00
report_context['total_amount'] = sum(total_amount)
2020-04-15 21:47:31 +02:00
report_context['company'] = Company(data['company'])
return report_context
class SaleIncomeDailyStart(ModelView):
'Sale Income Daily Start'
__name__ = 'sale_pos.sale_income_daily.start'
company = fields.Many2One('company.company', 'Company', required=True)
date = fields.Date('Date', required=True)
2020-07-04 20:56:48 +02:00
shop = fields.Many2One('sale.shop', 'Shop')
user = fields.Many2One('res.user', 'User')
2020-04-15 21:47:31 +02:00
# journal = fields.Many2One('account.statement.journal', 'Journal')
@staticmethod
def default_company():
return Transaction().context.get('company')
2020-07-04 15:08:07 +02:00
@staticmethod
def default_shop():
return Transaction().context.get('shop')
@staticmethod
def default_user():
return Transaction().user
2020-04-15 21:47:31 +02:00
@staticmethod
def default_date():
Date = Pool().get('ir.date')
return Date.today()
class SaleIncomeDaily(Wizard):
'Sale Income Daily'
__name__ = 'sale_pos.sale_income_daily'
start = StateView('sale_pos.sale_income_daily.start',
'sale_pos.sale_income_daily_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('sale_pos.sale_income_daily_report')
def do_print_(self, action):
shop_id, user_id = None, None
if self.start.user:
user_id = self.start.user.id
2020-04-15 21:47:31 +02:00
if self.start.shop:
shop_id = self.start.shop.id
report_context = {
'company': self.start.company.id,
'date': self.start.date,
'user': user_id,
2020-04-15 21:47:31 +02:00
'shop': shop_id,
}
return action, report_context
def transition_print_(self):
return 'end'
class SaleIncomeDailyReport(Report):
'Income Daily Report'
__name__ = 'sale_pos.sale_income_daily_report'
@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()
Invoice = pool.get('account.invoice')
Voucher = pool.get('account.voucher')
Company = pool.get('company.company')
company = Company(data['company'])
Statement = pool.get('account.statement')
Shop = pool.get('sale.shop')
User = pool.get('res.user')
2020-07-15 14:09:28 +02:00
records = []
2021-02-16 05:21:40 +01:00
devices = []
statements_ = {}
2020-07-15 14:09:28 +02:00
advances = []
total_advances = []
advances_cash = []
advances_electronic = []
total_statements = []
statement_cash = []
statement_electronic = []
advances_voucher = []
total_payments = []
payments = []
payments_voucher = []
payments_cash = []
payments_electronic = []
2020-04-15 21:47:31 +02:00
2020-07-04 20:56:48 +02:00
dom_statement = [
2020-04-15 21:47:31 +02:00
('date', '=', data['date']),
2020-07-04 20:56:48 +02:00
]
if data['shop']:
dom_statement.append(('sale_device.shop.id', '=', data['shop']))
statements = Statement.search(dom_statement)
2020-04-15 21:47:31 +02:00
user_id = Transaction().user
user = User(user_id)
for statement in statements:
st_amount = sum(l.amount for l in statement.lines)
2021-02-16 05:35:42 +01:00
to_add = {
'journal': statement.journal.name,
'turn': statement.turn,
'total_amount': st_amount,
}
2021-02-16 05:21:40 +01:00
if statement.sale_device.id not in statements_.keys():
2021-02-16 05:35:42 +01:00
statements_[statement.sale_device.id] = {
2021-02-16 05:21:40 +01:00
'name': statement.sale_device.name,
'total': [st_amount],
2021-02-16 05:35:42 +01:00
'records': [to_add]
}
2021-02-16 05:21:40 +01:00
else:
statements_[statement.sale_device.id]['total'].append(st_amount)
2021-02-16 05:35:42 +01:00
statements_[statement.sale_device.id]['records'].append(to_add)
2020-04-15 21:47:31 +02:00
total_statements.append(st_amount)
for l in statement.lines:
2020-07-10 00:13:04 +02:00
if l.statement.journal.kind == 'cash':
statement_cash.append(l.amount)
else:
statement_electronic.append(l.amount)
2020-04-15 21:47:31 +02:00
dom_vouchers = [
2020-07-04 15:08:07 +02:00
('move', '!=', None),
('move.post_date', '=', data['date']),
2020-04-15 21:47:31 +02:00
]
if data['user']:
dom_vouchers.append(
('create_uid', '=', data['user']),
)
2020-04-15 21:47:31 +02:00
vouchers = Voucher.search(dom_vouchers)
for v in vouchers:
cash = 0
electronic = 0
for l in v.lines:
2020-07-15 14:09:28 +02:00
if v.voucher_type == 'receipt':
if v.payment_mode.payment_type == 'cash':
advances_cash.append(l.amount)
cash = l.amount
else:
advances_electronic.append(l.amount)
electronic = l.amount
advances_voucher.append(l.amount)
advances.append({
'number': l.voucher.number,
'reference': l.detail,
'party': l.party.name if l.party else l.voucher.party.name,
'total_amount': l.amount,
'payment_mode': l.voucher.payment_mode.name,
'cash': cash,
'electronic': electronic,
})
total_advances.append(l.amount)
if v.voucher_type == 'payment':
amount_ = l.amount * (-1)
if v.payment_mode.payment_type == 'cash':
payments_cash.append(amount_)
cash = amount_
else:
payments_electronic.append(amount_)
electronic = amount_
payments_voucher.append(amount_)
payments.append({
'number': l.voucher.number,
'reference': l.detail,
'party': l.party.name if l.party else l.voucher.party.name,
'total_amount': amount_,
'payment_mode': l.voucher.payment_mode.name,
'cash': cash,
'electronic': electronic,
})
total_payments.append(amount_)
2020-04-15 21:47:31 +02:00
2020-07-04 20:56:48 +02:00
dom_invoices = [
2020-04-15 21:47:31 +02:00
('company', '=', data['company']),
('invoice_date', '=', data['date']),
('number', '!=', None),
2021-09-11 17:19:34 +02:00
# ('state', 'in', ['posted', 'paid', 'canceled', 'validated']),
2021-03-03 17:03:35 +01:00
('type', '=', 'out'),
2020-04-15 21:47:31 +02:00
]
shop_names = ''
if data['shop']:
shop_names = Shop(data['shop']).name
2020-07-04 20:56:48 +02:00
dom_invoices.append(
2020-04-15 21:47:31 +02:00
('shop', '=', data['shop'])
)
else:
shops = Shop.search([])
for s in shops:
shop_names += s.name + ', '
2020-07-04 20:56:48 +02:00
invoices = Invoice.search(dom_invoices, order=[('number', 'ASC')])
2020-04-15 21:47:31 +02:00
invoices_number = []
total_invoices_cash = []
total_invoices_electronic = []
total_invoices_credit = []
total_invoices_paid = []
2021-02-16 05:21:40 +01:00
devices = {}
2020-04-15 21:47:31 +02:00
total_invoices_amount = []
for invoice in invoices:
invoices_number.append(invoice.number)
cash = 0
electronic = 0
credit = 0
total_invoices_amount.append(invoice.total_amount)
2021-09-11 17:19:34 +02:00
if not invoice.sales:
continue
2020-04-15 21:47:31 +02:00
sale = invoice.sales[0]
2021-02-16 05:21:40 +01:00
device_id = sale.sale_device.id
2020-04-15 21:47:31 +02:00
if not sale.payments:
total_invoices_credit.append(invoice.amount_to_pay)
credit = invoice.amount_to_pay
else:
for p in sale.payments:
if p.statement.date == data['date']:
if p.statement.journal.kind == 'cash':
cash += p.amount
total_invoices_cash.append(p.amount)
else:
electronic += p.amount
total_invoices_electronic.append(p.amount)
total_invoices_paid.append(p.amount)
2021-02-16 05:21:40 +01:00
paid = cash + electronic
2020-04-15 21:47:31 +02:00
inv = {
'number': invoice.number,
'reference': invoice.reference,
'party': invoice.party.name,
'total_amount': invoice.total_amount,
'credit': credit,
'cash': cash,
'electronic': electronic,
2021-02-16 05:21:40 +01:00
'paid': paid,
2020-04-15 21:47:31 +02:00
'state': invoice.state_string,
2021-02-13 21:39:09 +01:00
'sale_device': sale.sale_device.name,
2020-04-15 21:47:31 +02:00
}
records.append(inv)
2021-02-16 05:21:40 +01:00
try:
devices[device_id]['total'].append(invoice.total_amount)
devices[device_id]['cash'].append(cash)
devices[device_id]['electronic'].append(electronic)
2021-02-16 05:35:42 +01:00
devices[device_id]['credit'].append(credit)
2021-02-16 05:21:40 +01:00
devices[device_id]['paid'].append(paid)
except:
devices[device_id] = {
'name': sale.sale_device.name,
'total': [invoice.total_amount],
'credit': [credit],
'cash': [cash],
'electronic': [electronic],
'paid': [paid],
}
2020-04-15 21:47:31 +02:00
advances_cash_ = sum(advances_cash)
advances_electronic_ = sum(advances_electronic)
statement_cash_ = sum(statement_cash)
statement_electronic_ = sum(statement_electronic)
2020-07-15 14:09:28 +02:00
payments_cash_ = sum(payments_cash)
payments_electronic_ = sum(payments_electronic)
2020-04-15 21:47:31 +02:00
report_context['records'] = records
2021-02-16 05:21:40 +01:00
report_context['devices'] = devices.values()
2020-04-15 21:47:31 +02:00
report_context['advances'] = advances
2021-02-16 05:35:42 +01:00
report_context['statements'] = statements_.values()
2020-04-15 21:47:31 +02:00
report_context['date'] = data['date']
report_context['company'] = company.party.name
report_context['shop'] = shop_names
report_context['user'] = user.name
report_context['print_date'] = datetime.now()
report_context['statement_cash'] = statement_cash_
report_context['statement_electronic'] = statement_electronic_
report_context['total_invoices_amount'] = sum(total_invoices_amount)
report_context['total_invoices_cash'] = sum(total_invoices_cash)
report_context['total_invoices_electronic'] = sum(total_invoices_electronic)
report_context['total_invoices_credit'] = sum(total_invoices_credit)
report_context['total_invoices_paid'] = sum(total_invoices_paid)
report_context['total_advances'] = sum(total_advances)
report_context['advances_cash'] = advances_cash_
report_context['advances_electronic'] = advances_electronic_
report_context['advances_voucher'] = sum(advances_voucher)
report_context['total_statements'] = sum(total_statements)
report_context['start_invoice'] = min(invoices_number) if invoices_number else ''
report_context['end_invoice'] = max(invoices_number) if invoices_number else ''
report_context['total_cash'] = advances_cash_ + statement_cash_
report_context['total_electronic'] = advances_electronic_ + statement_electronic_
2020-07-15 14:09:28 +02:00
report_context['total_payments'] = sum(total_payments)
report_context['payments_voucher'] = sum(payments_voucher)
report_context['payments_cash'] = payments_cash_
report_context['payments_electronic'] = payments_electronic_
report_context['payments'] = payments
2020-04-15 21:47:31 +02:00
return report_context
2020-04-22 01:18:59 +02:00
2020-12-28 03:32:05 +01:00
class SaleByKindStart(ModelView):
'Sale by Kind Start'
__name__ = 'sale_pos.sale_by_kind.start'
company = fields.Many2One('company.company', 'Company', required=True)
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
2022-01-12 15:40:53 +01:00
start_time = fields.Time('Start Time')
end_time = fields.Time('End Time')
2020-12-28 03:32:05 +01:00
shop = fields.Many2One('sale.shop', 'Shop')
2022-02-04 14:57:12 +01:00
payment_terms = fields.Many2Many('account.invoice.payment_term', None, None,
'Payment Term')
kind = fields.Selection([
('', ''),
('delivery', 'Delivery'),
('take_away', 'Take Away'),
('to_table', 'To Table'),
('catering', 'Catering'),
], 'Kind Order',)
party = fields.Many2One('party.party', 'Party')
detailed_by_party = fields.Boolean('Detailed By Party')
2022-02-12 17:57:11 +01:00
including_tax = fields.Boolean('Including Tax')
2020-12-28 03:32:05 +01:00
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_shop():
return Transaction().context.get('shop')
@staticmethod
def default_date():
Date = Pool().get('ir.date')
return Date.today()
class SaleByKind(Wizard):
'Sale By Kind'
__name__ = 'sale_pos.sale_by_kind'
start = StateView('sale_pos.sale_by_kind.start',
'sale_pos.sale_by_kind_start_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('sale_pos.sale_by_kind_report')
def do_print_(self, action):
shop_id = None
if self.start.shop:
shop_id = self.start.shop.id
2022-02-04 14:57:12 +01:00
payment_terms = None
if self.start.payment_terms:
payment_terms = [p.id for p in self.start.payment_terms]
2020-12-28 03:32:05 +01:00
report_context = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
2022-01-12 15:40:53 +01:00
'start_time': self.start.start_time,
'end_time': self.start.end_time,
2020-12-28 03:32:05 +01:00
'shop': shop_id,
2022-02-04 14:57:12 +01:00
'payment_terms': payment_terms,
'party': self.start.party,
'kind': self.start.kind,
'detailed': self.start.detailed_by_party,
2022-02-12 17:57:11 +01:00
'including_tax': self.start.including_tax,
2020-12-28 03:32:05 +01:00
}
return action, report_context
def transition_print_(self):
return 'end'
class SaleByKindReport(Report):
'Sale by Kind Report'
__name__ = 'sale_pos.sale_by_kind_report'
@classmethod
2022-02-12 17:57:11 +01:00
def get_query(cls, data):
2020-12-28 03:32:05 +01:00
pool = Pool()
2022-01-15 00:00:16 +01:00
Shop = pool.get('sale.shop')
2022-02-07 18:50:54 +01:00
Invoice = pool.get('account.invoice')
2022-02-12 17:57:11 +01:00
Line = pool.get('account.invoice.line')
2022-02-04 14:57:12 +01:00
Party = pool.get('party.party')
2022-02-12 17:57:11 +01:00
InvoiceTax = pool.get('account.invoice.tax')
tables = {}
tables['invoice'] = invoice = Invoice.__table__()
tables['shop'] = shop = Shop.__table__()
tables['party'] = party = Party.__table__()
tables['invoicetax'] = invoicetax = InvoiceTax.__table__()
tables['invoice.line'] = line = Line.__table__()
columns_invoicetax = [
2022-08-01 23:13:07 +02:00
invoice.id.as_('invoice'),
Sum(Coalesce(invoicetax.amount, 0)).as_('amount'),
2022-02-12 17:57:11 +01:00
]
2022-08-01 23:13:07 +02:00
query = invoice.join(invoicetax, 'LEFT', condition=invoice.id==invoicetax.invoice).select(
2022-02-12 17:57:11 +01:00
*columns_invoicetax,
2022-08-01 23:13:07 +02:00
group_by=(invoice.id)
2022-02-12 17:57:11 +01:00
)
withs = {}
withs['with_invoicetax'] = with_invoicetax = With(query=query)
2022-02-02 13:43:53 +01:00
2022-02-12 17:57:11 +01:00
columns = [
invoice.shop.as_('shop_id'),
shop.name.as_('shop'),
]
2022-08-04 22:12:10 +02:00
group_by = (invoice.shop, shop.name)
2022-02-12 17:57:11 +01:00
from_item = invoice.join(
shop, condition=shop.id == invoice.shop
).join(party, condition=party.id == invoice.party
2022-08-20 17:27:16 +02:00
).join(with_invoicetax, 'LEFT', condition=invoice.id == with_invoicetax.invoice
2022-02-12 17:57:11 +01:00
)
return from_item, tables, columns, group_by, withs
2022-01-15 00:00:16 +01:00
2022-02-12 17:57:11 +01:00
@classmethod
def _where(cls, tables, data):
invoice = tables['invoice']
2022-01-15 00:00:16 +01:00
2022-02-07 18:50:54 +01:00
where = invoice.state.in_(['posted', 'paid', 'validated'])
where &= invoice.invoice_date >= data['start_date']
where &= invoice.invoice_date <= data['end_date']
2022-02-12 17:57:11 +01:00
where &= invoice.company == data['company']
where &= invoice.type == 'out'
2020-12-28 03:32:05 +01:00
2022-01-12 16:00:57 +01:00
if data['start_time'] and data['end_time']:
2022-02-15 15:46:29 +01:00
start_date = datetime.combine(data['start_date'], data['start_time']) + timedelta(hours=5)
end_date = datetime.combine(data['end_date'], data['end_time']) + timedelta(hours=5)
2022-01-15 00:00:16 +01:00
2022-02-07 18:50:54 +01:00
where &= invoice.create_date <= end_date
where &= invoice.create_date >= start_date
2020-12-28 03:32:05 +01:00
if data['shop']:
2022-02-07 18:50:54 +01:00
where &= invoice.shop == data['shop']
2022-02-04 14:57:12 +01:00
if data['party']:
2022-02-07 18:50:54 +01:00
where &= invoice.party == data['party']
2022-02-04 14:57:12 +01:00
if data['payment_terms']:
2022-02-07 18:50:54 +01:00
where &= invoice.payment_term.in_(data['payment_terms'])
2022-02-04 14:57:12 +01:00
if data['kind']:
2022-02-07 18:50:54 +01:00
where &= invoice.sale_kind == data['kind']
2022-02-12 17:57:11 +01:00
return where
2022-02-04 14:57:12 +01:00
2022-02-12 17:57:11 +01:00
@classmethod
def set_detailed_query(cls, tables, columns, group_by):
party = tables['party']
columns.extend([
party.id.as_('party_id'),
party.name.as_('party'),
])
group_by += (party.id, party.name)
2020-12-28 03:32:05 +01:00
2022-02-12 17:57:11 +01:00
return columns, group_by
2022-01-15 00:00:16 +01:00
2022-02-12 17:57:11 +01:00
@classmethod
def get_columns_kind(cls, tables, withs, type):
invoice = tables['invoice']
line = tables['invoice.line']
invoicetax = withs['with_invoicetax']
condition_case_other = ((invoice.sale_kind == '') | (invoice.sale_kind == Null))
kinds = ['to_table', 'take_away', 'delivery', 'catering', 'others']
columns_count = []
columns_line_amount = []
columns_invoice_amount = []
2022-01-15 00:00:16 +01:00
for k in kinds:
if k != 'others':
2022-02-12 17:57:11 +01:00
columns_count.extend([Sum(Case((invoice.sale_kind == k, 1), else_=0)).as_('sales_'+k)])
columns_line_amount.extend([Sum(Case((invoice.sale_kind == k, (line.quantity*line.unit_price)), else_=0)).as_('amount_'+k)])
columns_invoice_amount.extend([Sum(Case((invoice.sale_kind == k, (invoice.untaxed_amount_cache + invoicetax.amount)), else_=0)).as_('amount_'+k)])
2020-12-28 03:32:05 +01:00
else:
2022-02-12 17:57:11 +01:00
columns_count.extend([Sum(Case((condition_case_other, 1), else_=0)).as_('sales_'+k)])
columns_line_amount.extend([Sum(Case((condition_case_other, (line.quantity*line.unit_price)), else_=0)).as_('amount_'+k)])
columns_invoice_amount.extend([Sum(Case((condition_case_other, (invoice.untaxed_amount_cache + invoicetax.amount)), else_=0)).as_('amount_'+k)])
if type == 'count':
return columns_count
elif type == 'line_amount':
return columns_line_amount
else:
return columns_invoice_amount
2022-02-02 13:43:53 +01:00
2022-02-12 17:57:11 +01:00
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Company = pool.get('company.company')
company = Company(data['company'])
config = pool.get('sale.configuration')(1)
products_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)
from_item, tables, columns, group_by, withs = cls.get_query(data)
2022-02-19 14:36:17 +01:00
invoice = tables['invoice']
columns.extend([Count(invoice.number).as_('sales_total')])
2022-02-02 13:43:53 +01:00
2022-02-04 14:57:12 +01:00
if data['detailed']:
2022-02-12 17:57:11 +01:00
columns, group_by = cls.set_detailed_query(
tables, columns, group_by)
2022-02-02 13:43:53 +01:00
2022-02-12 17:57:11 +01:00
columns.extend(cls.get_columns_kind(tables, withs, 'count'))
if data['including_tax']:
invoicetax = withs['with_invoicetax']
columns.extend(cls.get_columns_kind(tables, withs, 'invoice_amount'))
columns.extend([Sum(invoice.untaxed_amount_cache + invoicetax.amount).as_('amount_total')])
query = from_item.select(*columns, where=cls._where(tables, data), group_by=group_by, with_=withs.values())
records, totals = cls.get_values(query, {}, {}, data['detailed'])
if not data['including_tax']:
from_item, tables, columns, group_by, withs = cls.get_query(data)
where = cls._where(tables, data)
line = tables['invoice.line']
invoice = tables['invoice']
from_item = from_item.join(line, condition=line.invoice == invoice.id)
if len(products_exception) > 0:
where &= NotIn(line.product, products_exception)
2022-06-14 22:24:08 +02:00
columns.extend([Sum(line.quantity*line.unit_price).as_('amount_total')])
2022-02-12 17:57:11 +01:00
if data['detailed']:
columns, group_by = cls.set_detailed_query(
tables, columns, group_by)
columns.extend(cls.get_columns_kind(tables, withs, 'line_amount'))
query = from_item.select(*columns, where=where, group_by=group_by, with_=withs.values())
records, totals = cls.get_values(query, records, totals, data['detailed'])
2022-02-02 13:43:53 +01:00
report_context['records'] = records.values()
report_context['company'] = company.rec_name
report_context['total'] = totals if len(totals) > 1 else None
report_context['data'] = data
return report_context
@classmethod
2022-02-04 14:57:12 +01:00
def get_values(cls, query, records, totals, detailed):
2022-02-02 13:43:53 +01:00
cursor = Transaction().connection.cursor()
cursor.execute(*query)
2022-01-15 00:00:16 +01:00
columns = list(cursor.description)
result = cursor.fetchall()
for row in result:
2022-08-04 22:12:10 +02:00
key = row[0]
# key = str(row[0]) + '_' + str(row[2])
2022-02-04 14:57:12 +01:00
if detailed:
2022-02-12 17:57:11 +01:00
key = str(row[0]) + '_' + str(row[3])
2022-01-15 00:00:16 +01:00
row_dict = {}
for i, col in enumerate(columns):
if col.name.startswith('sales') or col.name.startswith('amount'):
try:
totals[col.name] += row[i]
except:
totals[col.name] = row[i]
row_dict[col.name] = row[i]
2022-02-02 13:43:53 +01:00
try:
2022-02-04 14:57:12 +01:00
records[key].update(row_dict)
2022-02-02 13:43:53 +01:00
except:
2022-02-04 14:57:12 +01:00
records[key] = row_dict
2022-02-02 13:43:53 +01:00
return records, totals
2020-12-28 03:32:05 +01:00
2020-04-22 01:18:59 +02:00
class DeleteSalesDraft(Wizard):
'Delete Sales Draft'
__name__ = 'sale_pos.delete_sales_draft'
start_state = 'delete_sales_draft'
delete_sales_draft = StateTransition()
@classmethod
def __setup__(cls):
super(DeleteSalesDraft, cls).__setup__()
def transition_delete_sales_draft(self):
2020-08-10 03:33:11 +02:00
cursor = Transaction().connection.cursor()
2020-04-22 01:18:59 +02:00
Sale = Pool().get('sale.sale')
sales = Sale.search(['AND',
2020-12-26 15:12:46 +01:00
['OR', [
('state', '=', 'draft'),
('invoice_number', '=', ''),
], [
('state', '=', 'draft'),
('invoice_number', '=', None),
],
]])
2020-04-22 01:18:59 +02:00
sales_delete = []
for sale in sales:
2020-08-10 03:33:11 +02:00
# if sale.lines:
# continue
2020-04-22 01:18:59 +02:00
if sale.payments:
continue
2020-08-10 03:33:11 +02:00
sales_delete.append(str(sale.id))
# Sale.delete(sales_delete)
cursor.execute("DELETE from sale_sale WHERE \
2020-12-26 15:12:46 +01:00
id in (%s)" % (', '.join(sales_delete)))
2020-04-22 01:18:59 +02:00
return 'end'
2020-08-27 21:18:37 +02:00
class PortfolioPaymentsStart(ModelView):
'Portfolio Payments Start'
__name__ = 'sale_pos.portfolio_payments.start'
company = fields.Many2One('company.company', 'Company', required=True)
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
user = fields.Many2One('res.user', 'User')
salesman = fields.Many2One('company.employee', 'Salesman')
is_post_date = fields.Boolean('Is Post Date')
2020-08-27 21:18:37 +02:00
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_start_date():
today_ = date.today()
2022-04-13 21:59:02 +02:00
# before_month = today_ - timedelta(month=1)
2020-08-27 21:18:37 +02:00
month = today_.month
day = today_.day
year = today_.year
if month == 1:
old_month = 12
else:
old_month = month - 1
2022-04-01 01:05:58 +02:00
_, end_day = calendar.monthrange(year, old_month)
return date(year, old_month, end_day)
2020-08-27 21:18:37 +02:00
@staticmethod
def default_end_date():
return date.today()
class PortfolioPayments(Wizard):
'Portfolio Payments'
__name__ = 'sale_pos.portfolio_payments'
start = StateView('sale_pos.portfolio_payments.start',
'sale_pos.portfolio_payments_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('sale_pos.portfolio_payments_report')
def do_print_(self, action):
data = {
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'company': self.start.company.id,
'company_name': self.start.company.rec_name,
'is_post_date': self.start.is_post_date,
2020-08-27 21:18:37 +02:00
}
if self.start.user:
data['user'] = self.start.user.id
if self.start.salesman:
data['salesman'] = self.start.salesman.id
2020-08-27 21:18:37 +02:00
return action, data
def transition_print_(self):
return 'end'
class PortfolioPaymentsReport(Report):
'Portfolio Payments Report'
__name__ = 'sale_pos.portfolio_payments_report'
@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-08-27 21:18:37 +02:00
pool = Pool()
VoucherLine = pool.get('account.voucher.line')
today = date.today()
dom_search = [
2020-08-27 21:18:37 +02:00
('voucher.company', '=', data['company']),
2021-08-17 17:13:00 +02:00
('voucher.state', '=', 'posted'),
2021-08-31 17:37:44 +02:00
('voucher.voucher_type', '=', 'receipt'),
2020-08-27 21:18:37 +02:00
]
if not data['is_post_date']:
dom_search.append([
('voucher.date', '>=', data['start_date']),
('voucher.date', '<=', data['end_date']), ]
)
else:
dom_search.append([
('voucher.move.post_date', '>=', data['start_date']),
('voucher.move.post_date', '<=', data['end_date']), ]
)
2020-08-27 21:18:37 +02:00
if data.get('user'):
dom_search.append(
('create_uid', '=', data['user']),
)
voucher_lines = []
for line in VoucherLine.search(dom_search):
voucher = line.voucher
move_line = line.move_line
if not move_line:
continue
2021-08-31 17:37:44 +02:00
origin = move_line.move_origin
2020-08-27 21:18:37 +02:00
expiration_date = move_line.maturity_date
2020-08-27 22:56:02 +02:00
expiration_days = (today - expiration_date).days \
if expiration_date else None
2020-08-27 21:18:37 +02:00
if origin and origin.__name__ == 'account.invoice':
2020-09-01 16:03:16 +02:00
shop = origin.shop.rec_name if origin.shop else ''
salesman = origin.salesman.rec_name if origin.salesman else ''
salesman_id = origin.salesman.id if origin.salesman else None
2020-08-27 21:18:37 +02:00
number = origin.number
invoice_date = origin.invoice_date
invoice_amount = origin.total_amount
invoice_balance = origin.amount_to_pay
else:
shop = ''
salesman = ''
2021-08-17 16:57:35 +02:00
salesman_id = ''
2020-08-27 21:18:37 +02:00
number = move_line.reference
invoice_date = ''
invoice_amount = move_line.amount
invoice_balance = None
values = {
2020-08-27 21:18:37 +02:00
'number': voucher.number,
'shop': shop,
'salesman': salesman,
'salesman_id': salesman_id,
2020-08-27 21:18:37 +02:00
'party_id': voucher.party.id_number_full,
'party_name': voucher.party.name,
'date': voucher.date,
'payment_mode': voucher.payment_mode.rec_name,
'check_number': voucher.check_number,
'payment_amount': line.amount,
'invoice_number': number,
'invoice_date': invoice_date,
'expiration_date': expiration_date,
'invoice_amount': invoice_amount,
'invoice_balance': invoice_balance,
'expiration_days': expiration_days,
2021-07-20 23:24:07 +02:00
'state': voucher.state_string,
}
2021-07-20 23:24:07 +02:00
if voucher.state == 'posted':
values['post_date'] = voucher.move.post_date
if data.get('salesman'):
if data['salesman'] == values['salesman_id']:
voucher_lines.append(values)
else:
voucher_lines.append(values)
2020-08-27 21:18:37 +02:00
report_context['records'] = voucher_lines
report_context['company'] = data['company_name']
report_context['sum_amount'] = sum([obj['payment_amount'] for obj in voucher_lines])
return report_context
2021-05-18 17:27:56 +02:00
class SaleGenerateShipment(Wizard):
"""
Sale Generate Shipment
"""
__name__ = 'sale.sale.generate_shipment'
start_state = 'generate_shipment'
generate_shipment = StateTransition()
@classmethod
def __setup__(cls):
super(SaleGenerateShipment, cls).__setup__()
def transition_generate_shipment(self):
Sale = Pool().get('sale.sale')
ids = Transaction().context['active_ids']
if ids:
2021-05-18 17:36:11 +02:00
sales = Sale.browse(ids)
for sale in sales:
2021-05-20 15:38:52 +02:00
if sale.shipment_state != 'none':
2021-06-22 20:38:42 +02:00
continue
2022-06-23 17:01:47 +02:00
if sale.total_amount_cache < 0 if sale.total_amount_cache else sale.total_amount < 0:
2021-05-18 17:36:11 +02:00
sale.create_shipment('return')
sale.set_shipment_state()
2021-05-20 15:38:52 +02:00
else:
2021-05-18 17:36:11 +02:00
sale.create_shipment('out')
sale.set_shipment_state()
2021-05-18 17:27:56 +02:00
return 'end'
2021-12-20 21:35:30 +01:00
class SalesCostsStart(ModelView):
'Sales Costs Start'
__name__ = 'sale_pos.sales_costs.start'
company = fields.Many2One('company.company', 'Company', required=True)
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
shop = fields.Many2One('sale.shop', 'Shop')
@staticmethod
def default_company():
return Transaction().context.get('company')
class SalesCosts(Wizard):
'Sales Costs'
__name__ = 'sale_pos.sales_costs'
start = StateView('sale_pos.sales_costs.start',
'sale_pos.sales_costs_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True),
])
print_ = StateReport('sale_pos.sales_costs_report')
def do_print_(self, action):
shop_id = None
if self.start.shop:
shop_id = self.start.shop.id
data = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'shop': shop_id,
}
return action, data
def transition_print_(self):
return 'end'
class SalesCostsReport(Report):
__name__ = 'sale_pos.sales_costs_report'
@classmethod
def get_line(cls, line, date_, number, origin):
return {
'date': date_,
'move': number,
'party': line.party.name if line.party else '',
'reference': line.reference,
'description': line.description,
'origin': origin,
'debit': line.debit,
'credit': line.credit,
}
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
# Invoice = pool.get('account.invoice')
InvoiceLine = pool.get('account.invoice.line')
Company = pool.get('company.company')
Shop = pool.get('sale.shop')
company = Company(data['company'])
2022-01-05 16:24:26 +01:00
shop_name = ''
if data['shop']:
shop = Shop(data['shop'])
shop_name = shop.name
2021-12-20 21:35:30 +01:00
dom = [
('invoice.invoice_date', '>=', data['start_date']),
('invoice.invoice_date', '<=', data['end_date']),
('invoice.move', '!=', None),
('invoice_type', '=', 'out'),
('type', '=', 'line'),
]
if data['shop']:
dom.append(('invoice.shop', '=', data['shop']))
lines = InvoiceLine.search_read(dom, fields_names=[
'product', 'product.rec_name', 'product.code', 'quantity',
'unit_price', 'unit.symbol', 'product.cost_price'
])
records = {}
total_cost = []
total_income = []
append_cost = total_cost.append
append_income = total_income.append
for line in lines:
qty, unit_price = line['quantity'], line['unit_price']
cost_price = line['product.']['cost_price']
income_amount = qty * float(unit_price)
cost_amount = qty * float(cost_price)
append_cost(cost_amount)
append_income(income_amount)
try:
rec_product = records[line['product']]
rec_product['qty'].append(qty)
rec_product['income_amount'].append(income_amount)
rec_product['cost_amount'].append(cost_amount)
except:
code, name = line['product.']['code'], line['product.']['rec_name']
records[line['product']] = {
'code': code,
'name': name,
'category': '',
'uom': line['unit.']['symbol'],
'qty': [qty],
'cost_price': cost_price,
'income_amount': [income_amount],
'cost_amount': [cost_amount],
}
2022-01-05 16:20:54 +01:00
report_context['shop'] = shop_name
2021-12-20 21:35:30 +01:00
report_context['company'] = company
report_context['records'] = records.values()
report_context['total_cost'] = total_cost
report_context['total_income'] = total_income
return report_context
2022-02-04 04:40:32 +01:00
class WizardSalePayment(metaclass=PoolMeta):
__name__ = 'sale.payment'
def transition_pay_(self):
res = super(WizardSalePayment, self).transition_pay_()
Sale = Pool().get('sale.sale')
active_id = Transaction().context.get('active_id', False)
sale = Sale(active_id)
if self.start.do_invoice:
Sale.workflow_to_end([sale])
return res
2022-04-29 17:30:18 +02:00
class SalesAuditStart(ModelView):
'Sales Audit Start'
__name__ = 'sale_pos.sales_audit.start'
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
shop = fields.Many2One('sale.shop', 'Shop', required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class SalesAudit(Wizard):
'Sale Detailed'
__name__ = 'sale_pos.sales_audit'
start = StateView('sale_pos.sales_audit.start',
'sale_pos.sales_audit_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateAction('sale_pos.sales_audit_report')
def do_print_(self, action):
data = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
'shop': self.start.shop.id,
}
return action, data
def transition_print_(self):
return 'end'
class SalesAuditReport(Report):
__name__ = 'sale_pos.sales_audit_report'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Invoice = pool.get('account.invoice')
Sale = pool.get('sale.sale')
Company = pool.get('company.company')
Product = pool.get('product.product')
Shop = pool.get('sale.shop')
shop = Shop(data['shop'])
sales_dom = [
('sale_date', '>=', data['start_date']),
('sale_date', '<=', data['end_date']),
('company', '=', data['company']),
('shop', '=', data['shop'])
# ('state', 'in', ['posted', 'paid', 'validated']),
]
sales = Sale.search(sales_dom, order=[('sale_date', 'ASC')])
records = []
append_rec = records.append
for rec in sales:
ship_number = ""
ship_date = ""
ship_state = ""
inv_number = ""
inv_date = ""
inv_state = ""
move = ""
move_date = ""
sale_cost = []
if rec.shipments:
ship = rec.shipments[0]
ship_number = ship.number
ship_date = ship.effective_date
ship_state = ship.state
elif rec.shipment_returns:
ship = rec.shipment_returns[0]
ship_number = ship.number
ship_date = ship.effective_date
ship_state = ship.state
if rec.invoices:
inv = rec.invoices[0]
inv_number = inv.number
inv_date = inv.invoice_date
inv_state = inv.state_string
if inv.move:
move = inv.move.number
move_date = inv.move.date
for ln in inv.move.lines:
if ln.account.code[0] == '6':
sale_cost.append(ln.debit - ln.credit)
res = {
'sale': rec.number,
'party': rec.party.name,
'reference': rec.reference,
'untaxed_amount': rec.untaxed_amount_cache,
'paid': rec.paid_amount,
'sale_date': rec.sale_date,
'state': rec.state_string,
'ship_number': ship_number,
'ship_date': ship_date,
'ship_state': ship_state,
'inv_number': inv_number,
'inv_date': inv_date,
'inv_state': inv_state,
'account_move': move,
'move_date': move_date,
'sale_cost': sale_cost,
}
print(' sale cost ...', sale_cost)
append_rec(res)
report_context['records'] = records
report_context['shop'] = shop.name
report_context['company'] = Company(data['company'])
return report_context