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
|
2020-04-15 21:47:31 +02:00
|
|
|
from decimal import Decimal
|
|
|
|
from datetime import datetime, date
|
|
|
|
from itertools import chain
|
|
|
|
|
|
|
|
from sql import Table
|
|
|
|
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
|
|
|
|
|
|
|
|
__all__ = [
|
2021-02-09 17:17:01 +01:00
|
|
|
'SaleForceDraft', 'Sale', 'SaleLine', 'SaleReportSummary', 'SaleDetailed',
|
|
|
|
'SaleReportSummaryByParty', 'SalePaymentForm', 'SaleUpdateDateStart',
|
|
|
|
'SaleUpdateDate', 'SaleDetailedStart', 'SaleDetailedReport',
|
2020-04-15 21:47:31 +02:00
|
|
|
'WizardSalePayment', 'SaleIncomeDailyStart', 'SaleIncomeDaily',
|
2020-08-27 21:18:37 +02:00
|
|
|
'SaleIncomeDailyReport', 'DeleteSalesDraft', 'PortfolioPaymentsStart',
|
2020-12-28 03:32:05 +01:00
|
|
|
'PortfolioPayments', 'PortfolioPaymentsReport', 'SaleByKindStart',
|
2021-02-09 17:17:01 +01:00
|
|
|
'SaleByKind', 'SaleByKindReport',
|
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)
|
|
|
|
payments = fields.One2Many('account.statement.line', 'sale', 'Payments')
|
2020-12-09 04:53:04 +01:00
|
|
|
paid_amount = fields.Function(fields.Numeric('Paid Amount', digits=(16, 2)),
|
2020-04-15 21:47:31 +02:00
|
|
|
'get_paid_amount')
|
|
|
|
invoice_number = fields.Char('Invoice Number')
|
|
|
|
invoice_date = fields.Date('Invoice Date')
|
|
|
|
invoice = fields.Many2One('account.invoice', 'Invoice')
|
2021-02-09 17:17:01 +01:00
|
|
|
residual_amount = fields.Function(fields.Numeric('Residual Amount',
|
|
|
|
digits=(16, 2),
|
2020-04-15 21:47:31 +02:00
|
|
|
readonly=True), 'get_residual_amount')
|
|
|
|
sale_device = fields.Many2One('sale.device', 'Sale Device',
|
|
|
|
domain=[('shop', '=', Eval('shop'))],
|
|
|
|
depends=['shop'], states=STATES)
|
|
|
|
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)
|
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)
|
|
|
|
for fname in cls.party.on_change:
|
|
|
|
if fname not in cls.self_pick_up.on_change:
|
|
|
|
cls.self_pick_up.on_change.add(fname)
|
2021-02-09 17:17:01 +01:00
|
|
|
# for fname in (
|
|
|
|
# 'invoice_method', 'shipment_method'):
|
|
|
|
# fstates = getattr(cls, fname).states
|
|
|
|
# if fstates.get('readonly'):
|
|
|
|
# fstates['readonly'] = Or(fstates['readonly'], Eval('self_pick_up', False))
|
|
|
|
# else:
|
|
|
|
# fstates['readonly'] = Eval('self_pick_up', False)
|
|
|
|
# getattr(cls, fname).depends.append('self_pick_up')
|
|
|
|
# if hasattr(cls, 'carrier'):
|
|
|
|
# if 'invisible' not in cls.carrier.states:
|
|
|
|
# cls.carrier.states['invisible'] = Bool(Eval('self_pick_up'))
|
|
|
|
# else:
|
|
|
|
# invisible = cls.carrier.states['invisible']
|
|
|
|
# cls.carrier.states['invisible'] = Or(invisible,
|
|
|
|
# Bool(Eval('self_pick_up')))
|
2020-04-15 21:47:31 +02:00
|
|
|
cls._error_messages.update({
|
|
|
|
'invoice_posted': 'You can not force to draft a invoice paid!',
|
|
|
|
'not_customer_invoice': ('A customer invoice/refund '
|
|
|
|
'from sale device has not been created.'),
|
|
|
|
'delete_invoice_number': ('The sale "%s" can not be deleted because it has an invoice number "%s"'),
|
2020-05-04 17:54:17 +02:00
|
|
|
'sale_not_product': ('The sale "%s" dont have product '),
|
2021-02-09 17:17:01 +01:00
|
|
|
'missing_tax': ('Falta el impuesto IVA en "%s" '),
|
2020-04-15 21:47:31 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
cls._buttons.update({
|
|
|
|
'wizard_sale_payment': {
|
|
|
|
'invisible': Eval('state') == 'done',
|
|
|
|
'readonly': Not(Bool(Eval('lines'))),
|
|
|
|
},
|
|
|
|
'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
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_invoice_type():
|
|
|
|
config = Pool().get('sale.configuration')(1)
|
|
|
|
return config.default_invoice_type
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def process(cls, sales):
|
|
|
|
for sale in sales:
|
2021-02-09 17:17:01 +01:00
|
|
|
cls.recheck_taxes(sale)
|
2020-04-15 21:47:31 +02:00
|
|
|
cls.process_pos(sale)
|
|
|
|
super(Sale, cls).process(sales)
|
|
|
|
|
2021-02-09 17:17:01 +01:00
|
|
|
@classmethod
|
|
|
|
def recheck_taxes(cls, sale):
|
|
|
|
for line in sale.lines:
|
|
|
|
vat_required = None
|
2021-02-16 23:54:42 +01:00
|
|
|
if line.product and line.product.account_category:
|
2021-02-09 17:17:01 +01:00
|
|
|
for txr in line.product.account_category.customer_taxes_used:
|
|
|
|
if txr.type == 'percentage' and txr.rate > 0:
|
|
|
|
vat_required = txr.id
|
|
|
|
break
|
2021-02-16 23:54:42 +01:00
|
|
|
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:
|
|
|
|
cls.raise_user_error('missing_tax', 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)
|
|
|
|
|
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:
|
|
|
|
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):
|
|
|
|
pool = Pool()
|
|
|
|
Sequence = pool.get('ir.sequence.strict')
|
|
|
|
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
|
|
|
|
sequence_id = None
|
|
|
|
|
|
|
|
if not sale:
|
|
|
|
return
|
|
|
|
|
|
|
|
invoice = sale.create_invoice()
|
|
|
|
sale.set_invoice_state()
|
|
|
|
sequence_id = sale.get_sequence(sale)
|
|
|
|
if not sale.invoice_number and sale.invoice_method == 'order':
|
|
|
|
if sequence_id:
|
|
|
|
number = Sequence.get_id(sequence_id)
|
|
|
|
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
|
|
|
|
if invoice:
|
|
|
|
if sale.invoice_date:
|
|
|
|
inv_date = sale.invoice_date
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-04-15 21:47:31 +02:00
|
|
|
if sale.invoice_type:
|
2021-01-13 14:16:24 +01:00
|
|
|
# authorization_id = None
|
|
|
|
# if sale.untaxed_amount_cache > 0:
|
|
|
|
# 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
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
# to_write['invoice_type'] = sale.invoice_type
|
|
|
|
# to_write['authorization'] = authorization_id
|
|
|
|
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:
|
|
|
|
cls.raise_user_error('delete_invoice_number', (
|
|
|
|
sale.rec_name, sale.invoice_number)
|
|
|
|
)
|
|
|
|
super(Sale, cls).delete(sales)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ModelView.button_action('sale_pos.wizard_add_product')
|
|
|
|
def wizard_add_product(cls, sales):
|
|
|
|
pass
|
|
|
|
|
2021-02-09 17:17:01 +01:00
|
|
|
# @classmethod
|
|
|
|
# @ModelView.button
|
|
|
|
# def add_sum(cls, sales):
|
|
|
|
# Line = Pool().get('sale.line')
|
|
|
|
# lines = []
|
|
|
|
# for sale in sales:
|
|
|
|
# line = Line(
|
|
|
|
# sale=sale.id,
|
|
|
|
# type='subtotal',
|
|
|
|
# description='Subtotal',
|
|
|
|
# sequence=10000,
|
|
|
|
# )
|
|
|
|
# lines.append(line)
|
|
|
|
# Line.save(lines)
|
2020-04-15 21:47:31 +02:00
|
|
|
|
|
|
|
@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:
|
|
|
|
sale.create_shipment('out')
|
|
|
|
sale.set_shipment_state()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def post_invoices(cls, sale):
|
|
|
|
pool = Pool()
|
|
|
|
Date = pool.get('ir.date')
|
|
|
|
Invoice = pool.get('account.invoice')
|
|
|
|
Sequence = pool.get('ir.sequence.strict')
|
|
|
|
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()
|
2021-01-29 18:16:33 +01:00
|
|
|
if invoice.invoice_type not in ('P', 'M', 'C'):
|
2020-04-15 21:47:31 +02:00
|
|
|
Invoice.validate_invoice([invoice])
|
|
|
|
if hasattr(Invoice, 'submit'):
|
|
|
|
Invoice.submit([invoice])
|
|
|
|
|
2021-01-29 17:36:03 +01:00
|
|
|
if invoice.invoice_type in ('P', 'M', 'C') or (
|
2020-04-15 21:47:31 +02:00
|
|
|
hasattr(invoice, 'cufe') and invoice.cufe):
|
|
|
|
if sale.shop.workflow_invoice == 'validated':
|
|
|
|
Invoice.write([invoice], {'state': 'validated'})
|
|
|
|
else:
|
|
|
|
sale = cls.process_pos(sale)
|
|
|
|
if sale.invoice_number:
|
|
|
|
invoice.number = sale.invoice_number
|
|
|
|
else:
|
|
|
|
sequence_id = sale.get_sequence(sale)
|
|
|
|
if sequence_id:
|
|
|
|
number = Sequence.get_id(sequence_id)
|
|
|
|
sale.invoice_number = number
|
|
|
|
sale.save()
|
|
|
|
invoice.number = number
|
|
|
|
invoice.save()
|
|
|
|
Invoice.post([invoice])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def do_reconcile(cls, sales):
|
|
|
|
Reconciliation = Pool().get('account.move.reconciliation')
|
|
|
|
for sale in sales:
|
|
|
|
reconcile_lines = []
|
|
|
|
account_reconcile_id = None
|
|
|
|
invoice_id = None
|
|
|
|
if not sale.payments or not sale.number:
|
|
|
|
continue
|
|
|
|
try:
|
|
|
|
for invoice in sale.invoices:
|
|
|
|
if invoice.state == 'paid' or not invoice.move:
|
|
|
|
continue
|
|
|
|
invoice_id = invoice.id
|
|
|
|
|
|
|
|
account_reconcile_id = invoice.account.id
|
|
|
|
for line in invoice.payment_lines:
|
|
|
|
if not line.reconciliation and line.account.id == account_reconcile_id:
|
|
|
|
reconcile_lines.append(line.id)
|
|
|
|
for l in invoice.move.lines:
|
|
|
|
if l.account.id == account_reconcile_id:
|
|
|
|
reconcile_lines.append(l.id)
|
|
|
|
break
|
|
|
|
|
|
|
|
for st_line in sale.payments:
|
|
|
|
st_line.invoice = invoice_id
|
|
|
|
st_line.save()
|
|
|
|
if not st_line.move:
|
|
|
|
st_line.create_move()
|
|
|
|
|
|
|
|
for ml in st_line.move.lines:
|
|
|
|
if not ml.reconciliation and ml.account.id == account_reconcile_id:
|
|
|
|
reconcile_lines.append(ml.id)
|
|
|
|
|
|
|
|
if reconcile_lines:
|
|
|
|
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:
|
|
|
|
print('Warning: Sale number not processed %s' % sale.number)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def workflow_to_end(cls, sales):
|
|
|
|
_sales = cls.process_sale_pos(sales[0])
|
|
|
|
cls.post_invoices(_sales)
|
|
|
|
cls.do_stock_moves([_sales])
|
|
|
|
cls.do_reconcile([_sales])
|
|
|
|
cls.update_state([_sales])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_paid_amount(cls, sales, names):
|
|
|
|
result = {n: {s.id: Decimal(0) for s in sales} for n in names}
|
|
|
|
for name in names:
|
|
|
|
for sale in sales:
|
|
|
|
for payment in sale.payments:
|
|
|
|
result[name][sale.id] += payment.amount
|
|
|
|
result[name][sale.id] += sale.get_total_vouchers_amount()
|
|
|
|
return result
|
|
|
|
|
2021-01-04 13:50:22 +01:00
|
|
|
def get_residual_amount(self, name=None):
|
|
|
|
return (self.total_amount - self.paid_amount)
|
2020-04-15 21:47:31 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ModelView.button_action('sale_pos.wizard_sale_payment')
|
|
|
|
def wizard_sale_payment(cls, sales):
|
|
|
|
pass
|
|
|
|
|
|
|
|
@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['payments'] = None
|
|
|
|
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):
|
|
|
|
sequence_id = None
|
|
|
|
if sale.untaxed_amount_cache > 0:
|
|
|
|
if sale.invoice_type == 'C' and sale.shop.computer_authorization:
|
|
|
|
sequence_id = sale.shop.computer_authorization.sequence.id
|
|
|
|
elif sale.invoice_type == 'P' and sale.shop.pos_authorization:
|
|
|
|
sequence_id = sale.shop.pos_authorization.sequence.id
|
|
|
|
elif sale.invoice_type == 'M' and sale.shop.manual_authorization:
|
|
|
|
sequence_id = sale.shop.manual_authorization.sequence.id
|
|
|
|
elif sale.invoice_type in ['1','2','3'] and sale.shop.electronic_authorization:
|
|
|
|
sequence_id = sale.shop.electronic_authorization.sequence.id
|
|
|
|
elif sale.shop.invoice_sequence:
|
|
|
|
sequence_id = sale.shop.invoice_sequence.id
|
|
|
|
else:
|
|
|
|
if sale.shop.credit_note_electronic_authorization and sale.invoice_type in ['91', 'N']:
|
|
|
|
sequence_id = sale.shop.credit_note_electronic_authorization.sequence.id
|
|
|
|
elif sale.shop.debit_note_electronic_authorization and sale.invoice_type == '92':
|
|
|
|
sequence_id = sale.shop.debit_note_electronic_authorization.sequence.id
|
|
|
|
else:
|
|
|
|
if sale.shop.credit_note_sequence:
|
|
|
|
sequence_id = sale.shop.credit_note_sequence.id
|
|
|
|
return sequence_id
|
|
|
|
|
|
|
|
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),
|
|
|
|
])
|
|
|
|
if statements:
|
|
|
|
return statements[0].turn
|
|
|
|
|
2020-04-15 21:47:31 +02:00
|
|
|
|
|
|
|
class SaleLine(metaclass=PoolMeta):
|
|
|
|
__name__ = 'sale.line'
|
|
|
|
unit_price_w_tax = fields.Function(fields.Numeric('Unit Price with Tax',
|
|
|
|
digits=(16, Eval('_parent_sale', {}).get('currency_digits',
|
|
|
|
Eval('currency_digits', 2))),
|
|
|
|
states={
|
|
|
|
'invisible': Eval('type') != 'line',
|
|
|
|
},
|
|
|
|
depends=['type']), 'get_price_with_tax')
|
|
|
|
amount_w_tax = fields.Function(fields.Numeric('Amount with Tax',
|
|
|
|
digits=(16, Eval('_parent_sale', {}).get('currency_digits',
|
|
|
|
Eval('currency_digits', 2))),
|
|
|
|
states={
|
|
|
|
'invisible': ~Eval('type').in_(['line', 'subtotal']),
|
|
|
|
},
|
|
|
|
depends=['type']), 'get_price_with_tax')
|
|
|
|
unit_price_full = fields.Numeric('Unit Price Full',
|
|
|
|
digits=(16, Eval('_parent_sale', {}).get('currency_digits',
|
|
|
|
Eval('currency_digits', 2))),
|
|
|
|
states={
|
|
|
|
'invisible': Eval('type') != 'line',
|
2021-02-09 17:17:01 +01:00
|
|
|
'readonly': True,
|
|
|
|
},
|
2020-04-15 21:47:31 +02:00
|
|
|
depends=['type', 'currency_digits'])
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_currency_digits():
|
|
|
|
Company = Pool().get('company.company')
|
|
|
|
if Transaction().context.get('company'):
|
|
|
|
company = Company(Transaction().context['company'])
|
|
|
|
return company.currency.digits
|
|
|
|
return 2
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_currency():
|
|
|
|
Company = Pool().get('company.company')
|
|
|
|
if Transaction().context.get('company'):
|
|
|
|
company = Company(Transaction().context['company'])
|
|
|
|
return company.currency.id
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_price_with_tax(cls, lines, names):
|
|
|
|
pool = Pool()
|
|
|
|
Tax = pool.get('account.tax')
|
|
|
|
Company = pool.get('company.company')
|
|
|
|
amount_w_tax = {}
|
|
|
|
unit_price_w_tax = {}
|
|
|
|
|
|
|
|
def compute_amount_with_tax(line):
|
|
|
|
tax_amount = _ZERO
|
|
|
|
amount = _ZERO
|
|
|
|
|
|
|
|
if line.taxes:
|
|
|
|
tax_list = Tax.compute(line.taxes, line.unit_price or _ZERO,
|
|
|
|
line.quantity or 0.0)
|
|
|
|
|
|
|
|
tax_amount = sum([t['amount'] for t in tax_list], _ZERO)
|
|
|
|
|
|
|
|
if line.unit_price:
|
|
|
|
amount = line.unit_price * Decimal(line.quantity)
|
2020-12-10 13:10:08 +01:00
|
|
|
if hasattr(line.product, 'extra_tax') and line.product.extra_tax:
|
|
|
|
amount += line.product.extra_tax * Decimal(line.quantity)
|
|
|
|
|
2020-04-15 21:47:31 +02:00
|
|
|
return amount + tax_amount
|
|
|
|
|
|
|
|
for line in lines:
|
|
|
|
amount = _ZERO
|
|
|
|
unit_price = _ZERO
|
|
|
|
if line.sale:
|
|
|
|
currency = line.sale.currency
|
|
|
|
else:
|
|
|
|
# company = Company(Transaction().context.get('company'))
|
|
|
|
company = Company(1)
|
|
|
|
currency = company.currency
|
|
|
|
|
|
|
|
if line.type == 'line' and line.quantity:
|
|
|
|
amount = compute_amount_with_tax(line)
|
|
|
|
unit_price = amount / Decimal(str(line.quantity))
|
|
|
|
|
|
|
|
# Only compute subtotals if the two fields are provided to speed up
|
|
|
|
elif line.type == 'subtotal' and len(names) == 2:
|
|
|
|
for line2 in line.sale.lines:
|
|
|
|
if line2.type == 'line':
|
|
|
|
amount2 = compute_amount_with_tax(line2)
|
|
|
|
if currency:
|
|
|
|
amount2 = currency.round(amount2)
|
|
|
|
amount += amount2
|
|
|
|
elif line2.type == 'subtotal':
|
|
|
|
if line == line2:
|
|
|
|
break
|
|
|
|
amount = _ZERO
|
|
|
|
|
|
|
|
if currency:
|
|
|
|
amount = currency.round(amount)
|
|
|
|
|
|
|
|
amount_w_tax[line.id] = amount
|
|
|
|
unit_price_w_tax[line.id] = unit_price
|
|
|
|
|
|
|
|
result = {
|
|
|
|
'amount_w_tax': amount_w_tax,
|
|
|
|
'unit_price_w_tax': unit_price_w_tax,
|
|
|
|
}
|
|
|
|
for key in result.keys():
|
|
|
|
if key not in names:
|
|
|
|
del result[key]
|
|
|
|
return result
|
|
|
|
|
2021-02-09 17:17:01 +01:00
|
|
|
# @fields.depends('type', 'unit_price', 'quantity', 'taxes', 'sale',
|
|
|
|
# '_parent_sale.currency', 'product', 'amount')
|
|
|
|
# def on_change_with_unit_price_w_tax(self, name=None):
|
|
|
|
# if not self.sale:
|
|
|
|
# self.sale = Transaction().context.get('sale')
|
|
|
|
# return SaleLine.get_price_with_tax([self],
|
|
|
|
# ['unit_price_w_tax'])['unit_price_w_tax'][self.id]
|
|
|
|
|
|
|
|
# @fields.depends('type', 'unit_price', 'quantity', 'taxes', 'sale',
|
|
|
|
# '_parent_sale.currency', 'product', 'amount')
|
|
|
|
# def on_change_with_amount_w_tax(self, name=None):
|
|
|
|
# if not self.sale:
|
|
|
|
# self.sale = Transaction().context.get('sale')
|
|
|
|
# return SaleLine.get_price_with_tax([self],
|
|
|
|
# ['amount_w_tax'])['amount_w_tax'][self.id]
|
|
|
|
|
|
|
|
# @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
|
|
|
|
|
|
|
@fields.depends('product', 'quantity', 'unit', 'taxes',
|
|
|
|
'_parent_sale.currency', '_parent_sale.party',
|
|
|
|
'_parent_sale.sale_date', 'unit_price_full')
|
|
|
|
def on_change_quantity(self):
|
|
|
|
super(SaleLine, self).on_change_quantity()
|
|
|
|
if self.unit_price_full:
|
|
|
|
self.on_change_unit_price_full()
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
|
|
|
|
|
|
|
class StatementLine(metaclass=PoolMeta):
|
|
|
|
__name__ = 'account.statement.line'
|
|
|
|
sale = fields.Many2One('sale.sale', 'Sale', ondelete='RESTRICT')
|
|
|
|
|
|
|
|
|
|
|
|
class SaleReportSummary(metaclass=PoolMeta):
|
|
|
|
__name__ = 'sale_pos.sales_summary'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
report_context = super(SaleReportSummary, cls).get_context(records, data)
|
|
|
|
|
|
|
|
sum_untaxed_amount = Decimal(0)
|
|
|
|
sum_tax_amount = Decimal(0)
|
|
|
|
sum_total_amount = Decimal(0)
|
|
|
|
for sale in records:
|
|
|
|
sum_untaxed_amount += sale.untaxed_amount
|
|
|
|
sum_tax_amount += sale.tax_amount
|
|
|
|
sum_total_amount += sale.total_amount
|
|
|
|
|
|
|
|
report_context['sum_untaxed_amount'] = sum_untaxed_amount
|
|
|
|
report_context['sum_tax_amount'] = sum_tax_amount
|
|
|
|
report_context['sum_total_amount'] = sum_total_amount
|
|
|
|
report_context['company'] = report_context['user'].company
|
|
|
|
return report_context
|
|
|
|
|
|
|
|
|
|
|
|
class SaleReportSummaryByParty(metaclass=PoolMeta):
|
|
|
|
__name__ = 'sale_pos.sales_summary_by_party'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
parties = {}
|
2021-02-09 17:17:01 +01:00
|
|
|
report_context = super(SaleReportSummaryByParty, cls).get_context(
|
|
|
|
records, data
|
|
|
|
)
|
2020-04-15 21:47:31 +02:00
|
|
|
|
|
|
|
report_context['start_date'] = report_context['end_date'] = \
|
|
|
|
records[0].sale_date if records else None
|
|
|
|
|
|
|
|
sum_untaxed_amount = Decimal(0)
|
|
|
|
sum_tax_amount = Decimal(0)
|
|
|
|
sum_total_amount = Decimal(0)
|
|
|
|
for sale in records:
|
|
|
|
sum_untaxed_amount += sale.untaxed_amount
|
|
|
|
sum_tax_amount += sale.tax_amount
|
|
|
|
sum_total_amount += sale.total_amount
|
|
|
|
if sale.party.id not in parties.keys():
|
|
|
|
party = sale.party
|
|
|
|
party.name = sale.party.full_name
|
|
|
|
party.untaxed_amount = sale.untaxed_amount
|
|
|
|
party.tax_amount = sale.tax_amount
|
|
|
|
party.total_amount = sale.total_amount
|
|
|
|
party.currency = sale.currency
|
|
|
|
else:
|
|
|
|
party = parties.get(sale.party.id)
|
|
|
|
party.untaxed_amount += sale.untaxed_amount
|
|
|
|
party.tax_amount += sale.tax_amount
|
|
|
|
party.total_amount += sale.total_amount
|
|
|
|
parties[sale.party.id] = party
|
|
|
|
if sale.sale_date:
|
|
|
|
if not report_context['start_date'] or report_context['start_date'] > sale.sale_date:
|
|
|
|
report_context['start_date'] = sale.sale_date
|
|
|
|
if not report_context['end_date'] or report_context['end_date'] < sale.sale_date:
|
|
|
|
report_context['end_date'] = sale.sale_date
|
|
|
|
|
|
|
|
report_context['parties'] = parties.values()
|
|
|
|
report_context['sum_untaxed_amount'] = sum_untaxed_amount
|
|
|
|
report_context['sum_tax_amount'] = sum_tax_amount
|
|
|
|
report_context['sum_total_amount'] = sum_total_amount
|
|
|
|
report_context['company'] = report_context['user'].company
|
|
|
|
return report_context
|
|
|
|
|
|
|
|
|
2021-02-09 17:17:01 +01:00
|
|
|
# class AddProductForm(ModelView):
|
|
|
|
# 'Add Product Form'
|
|
|
|
# __name__ = 'sale_pos.add_product_form'
|
|
|
|
# sale = fields.Many2One('sale.sale', 'Sale')
|
|
|
|
# lines = fields.One2Many('sale.line', None, 'Lines',
|
|
|
|
# context={'sale': Eval('sale')}, depends=['sale'],)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# class WizardAddProduct(Wizard):
|
|
|
|
# 'Wizard Add Product'
|
|
|
|
# __name__ = 'sale_pos.add_product'
|
|
|
|
# start = StateView('sale_pos.add_product_form',
|
|
|
|
# 'sale_pos.add_product_view_form', [
|
|
|
|
# Button('Cancel', 'end', 'tryton-cancel'),
|
|
|
|
# Button('Add and New', 'add_new_', 'tryton-go-jump', default=True),
|
|
|
|
# Button('Add', 'add_', 'tryton-ok'),
|
|
|
|
# ])
|
|
|
|
# add_new_ = StateTransition()
|
|
|
|
# add_ = StateTransition()
|
|
|
|
#
|
|
|
|
# def default_start(self, fields):
|
|
|
|
# return {
|
|
|
|
# 'sale': Transaction().context.get('active_id'),
|
|
|
|
# }
|
|
|
|
#
|
|
|
|
# def add_lines(self):
|
|
|
|
# for line in self.start.lines:
|
|
|
|
# line.sale = Transaction().context.get('active_id', False)
|
|
|
|
# line.save()
|
|
|
|
#
|
|
|
|
# def transition_add_new_(self):
|
|
|
|
# self.add_lines()
|
|
|
|
# return 'start'
|
|
|
|
#
|
|
|
|
# def transition_add_(self):
|
|
|
|
# self.add_lines()
|
|
|
|
# return 'end'
|
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__()
|
|
|
|
cls._error_messages.update({
|
|
|
|
'with_electronic_invoice': 'The electronic invoice already exist!',
|
|
|
|
})
|
|
|
|
|
|
|
|
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')
|
|
|
|
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)
|
|
|
|
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':
|
|
|
|
self.raise_user_error('with_electronic_invoice')
|
|
|
|
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(
|
|
|
|
columns=[sale_table.state],
|
|
|
|
values=['draft'],
|
|
|
|
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__()
|
2020-05-04 17:50:58 +02:00
|
|
|
# cls._error_messages.update({
|
|
|
|
# 'sale_not_product': ('The sale "%s" dont have product '),
|
|
|
|
# })
|
2020-04-15 21:47:31 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
report_context = super(SaleDetailedReport, cls).get_context(records, data)
|
|
|
|
pool = Pool()
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
sales_line_dom = [
|
2021-02-17 19:38:45 +01:00
|
|
|
('invoice.invoice_date', '>=', data['start_date']),
|
|
|
|
('invoice.invoice_date', '<=', data['end_date']),
|
|
|
|
('product', '!=', None),
|
|
|
|
('invoice.company', '=', data['company']),
|
|
|
|
('invoice.state', 'in', ['posted', 'paid', 'validated']),
|
2020-04-15 21:47:31 +02:00
|
|
|
]
|
|
|
|
if data['salesman']:
|
|
|
|
sales_line_dom.append(
|
2021-02-17 19:38:45 +01:00
|
|
|
('invoice.salesman', '=', data['salesman'])
|
2020-04-15 21:47:31 +02:00
|
|
|
)
|
|
|
|
if data['shop']:
|
|
|
|
sales_line_dom.append(
|
2021-02-17 19:38:45 +01:00
|
|
|
('invoice.shop', '=', data['shop'])
|
2020-04-15 21:47:31 +02:00
|
|
|
)
|
|
|
|
if data['party']:
|
|
|
|
sales_line_dom.append(
|
2021-02-17 19:38:45 +01:00
|
|
|
('invoice.party', '=', data['party'])
|
2020-04-15 21:47:31 +02:00
|
|
|
)
|
|
|
|
if data['product']:
|
|
|
|
sales_line_dom.append(
|
|
|
|
('product', '=', data['product'])
|
2021-02-17 19:38:45 +01:00
|
|
|
)
|
2020-04-15 21:47:31 +02:00
|
|
|
|
2021-02-17 19:38:45 +01:00
|
|
|
start_lines = InvoiceLine.search(sales_line_dom, order=[
|
|
|
|
('invoice.invoice_date', 'ASC')]
|
|
|
|
)
|
|
|
|
untaxed_amount = []
|
|
|
|
subtotal_amount = []
|
2020-04-15 21:47:31 +02:00
|
|
|
for line in start_lines:
|
2020-05-04 18:00:02 +02:00
|
|
|
if line.type == 'line' and not line.product:
|
2021-02-17 19:38:45 +01:00
|
|
|
Sale.raise_user_error('sale_not_product', line.invoice.number)
|
|
|
|
|
|
|
|
amount = line.quantity * float(line.product.sale_price_taxed)
|
|
|
|
line.subtotal_amount = amount
|
|
|
|
untaxed_amount.append(line.amount)
|
|
|
|
subtotal_amount.append(amount)
|
2020-04-15 21:47:31 +02:00
|
|
|
|
2021-02-17 19:38:45 +01:00
|
|
|
report_context['records'] = start_lines
|
|
|
|
report_context['untaxed_amount'] = sum(untaxed_amount)
|
|
|
|
report_context['subtotal_amount'] = sum(subtotal_amount)
|
2020-04-15 21:47:31 +02:00
|
|
|
report_context['company'] = Company(data['company'])
|
|
|
|
return report_context
|
|
|
|
|
|
|
|
|
|
|
|
class SalePaymentForm(ModelView):
|
|
|
|
'Sale Payment Form'
|
|
|
|
__name__ = 'sale.payment.form'
|
|
|
|
journal = fields.Many2One('account.statement.journal', 'Statement Journal',
|
|
|
|
domain=[
|
|
|
|
('id', 'in', Eval('journals', [])),
|
|
|
|
], depends=['journals'], required=True)
|
|
|
|
journals = fields.One2Many('account.statement.journal', None,
|
|
|
|
'Allowed Statement Journals')
|
|
|
|
payment_amount = fields.Numeric('Payment amount', required=True,
|
|
|
|
digits=(16, Eval('currency_digits', 2)),
|
|
|
|
depends=['currency_digits'])
|
|
|
|
currency_digits = fields.Integer('Currency Digits')
|
|
|
|
party = fields.Many2One('party.party', 'Party', readonly=True)
|
|
|
|
require_voucher = fields.Boolean('Require Voucher',
|
|
|
|
depends=['journal'])
|
|
|
|
voucher = fields.Char('Voucher Number', states={
|
|
|
|
'required': Eval('require_voucher', False),
|
|
|
|
'invisible': Not(Eval('require_voucher', False)),
|
|
|
|
}, depends=['require_voucher'])
|
|
|
|
self_pick_up = fields.Boolean('Self Pick Up', readonly=True)
|
|
|
|
do_invoice = fields.Boolean('Do Invoice')
|
|
|
|
|
|
|
|
@fields.depends('journal', 'voucher')
|
|
|
|
def on_change_with_require_voucher(self):
|
|
|
|
if self.journal:
|
|
|
|
return self.journal.require_voucher
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_require_voucher(cls):
|
|
|
|
return False
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def default_do_invoice(cls):
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
class WizardSalePayment(Wizard):
|
|
|
|
'Wizard Sale Payment'
|
|
|
|
__name__ = 'sale.payment'
|
|
|
|
start = StateView('sale.payment.form',
|
|
|
|
'sale_pos.sale_payment_view_form', [
|
|
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
|
|
Button('Pay', 'pay_', 'tryton-ok', default=True),
|
|
|
|
])
|
|
|
|
pay_ = StateTransition()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __setup__(cls):
|
|
|
|
super(WizardSalePayment, cls).__setup__()
|
|
|
|
cls._error_messages.update({
|
|
|
|
'not_sale_device': ('You have not defined a sale device for '
|
|
|
|
'your user.'),
|
|
|
|
'not_draft_statement': ('A draft statement for "%s" payments '
|
|
|
|
'has not been created.'),
|
|
|
|
'party_without_account_receivable': 'Party %s has no any '
|
|
|
|
'account receivable defined. Please, assign one.',
|
|
|
|
})
|
|
|
|
|
|
|
|
def default_start(self, fields):
|
|
|
|
pool = Pool()
|
|
|
|
Sale = pool.get('sale.sale')
|
|
|
|
User = pool.get('res.user')
|
|
|
|
sale = Sale(Transaction().context['active_id'])
|
|
|
|
user = User(Transaction().user)
|
|
|
|
sale_device = sale.sale_device or user.sale_device or False
|
|
|
|
if user.id != 0 and not sale_device:
|
|
|
|
self.raise_user_error('not_sale_device')
|
|
|
|
return {
|
|
|
|
'journal': sale_device.journal.id
|
|
|
|
if sale_device.journal else None,
|
|
|
|
'journals': [j.id for j in sale_device.journals],
|
|
|
|
'payment_amount': sale.total_amount - sale.paid_amount
|
|
|
|
if sale.paid_amount else sale.total_amount,
|
|
|
|
'currency_digits': sale.currency_digits,
|
|
|
|
'party': sale.party.id,
|
|
|
|
}
|
|
|
|
|
|
|
|
def transition_pay_(self):
|
|
|
|
pool = Pool()
|
|
|
|
User = pool.get('res.user')
|
|
|
|
user = User(Transaction().user)
|
|
|
|
Sale = pool.get('sale.sale')
|
|
|
|
Statement = pool.get('account.statement')
|
|
|
|
StatementLine = pool.get('account.statement.line')
|
|
|
|
active_id = Transaction().context.get('active_id', False)
|
|
|
|
sale = Sale(active_id)
|
|
|
|
|
|
|
|
form = self.start
|
|
|
|
device_id = user.sale_device.id if user.sale_device else sale.sale_device.id
|
|
|
|
statements = Statement.search([
|
|
|
|
('journal', '=', form.journal),
|
|
|
|
('state', '=', 'draft'),
|
|
|
|
('sale_device', '=', device_id),
|
|
|
|
], order=[('date', 'DESC')])
|
|
|
|
if not statements:
|
|
|
|
self.raise_user_error('not_draft_statement', (form.journal.name,))
|
|
|
|
|
|
|
|
if not sale.number:
|
|
|
|
Sale.set_number([sale])
|
|
|
|
|
|
|
|
account = (sale.party.account_receivable
|
|
|
|
and sale.party.account_receivable.id
|
|
|
|
or self.raise_user_error('party_without_account_receivable',
|
|
|
|
error_args=(sale.party.name,)))
|
|
|
|
|
|
|
|
if form.payment_amount:
|
|
|
|
payment = StatementLine(
|
|
|
|
statement=statements[0].id,
|
|
|
|
date=date.today(),
|
|
|
|
amount=form.payment_amount,
|
|
|
|
party=sale.party.id,
|
|
|
|
account=account,
|
|
|
|
description=self.start.voucher,
|
|
|
|
sale=active_id,
|
|
|
|
# number=self.start.voucher,
|
|
|
|
# voucher=self.start.voucher,
|
|
|
|
)
|
|
|
|
payment.save()
|
|
|
|
|
|
|
|
if sale.total_amount != sale.paid_amount:
|
|
|
|
return 'start'
|
|
|
|
sale.save()
|
|
|
|
if self.start.do_invoice:
|
|
|
|
# for inv in sale.invoices:
|
|
|
|
# if inv.state == 'posted':
|
|
|
|
# inv.write([inv], {'state': 'draft'})
|
|
|
|
Sale.workflow_to_end([sale])
|
|
|
|
return 'end'
|
|
|
|
|
|
|
|
|
|
|
|
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')
|
2020-07-07 16:18:55 +02:00
|
|
|
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')
|
|
|
|
|
2020-07-07 16:18:55 +02:00
|
|
|
@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):
|
2020-07-07 16:18:55 +02:00
|
|
|
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,
|
2020-07-07 16:18:55 +02:00
|
|
|
'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
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
report_context = super(SaleIncomeDailyReport, cls).get_context(records, data)
|
|
|
|
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
|
|
|
]
|
2020-07-07 16:18:55 +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-02-16 05:21:40 +01:00
|
|
|
('state', 'in', ['posted', 'paid', 'canceled', 'validated']),
|
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)
|
|
|
|
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)
|
|
|
|
shop = fields.Many2One('sale.shop', 'Shop')
|
|
|
|
|
|
|
|
@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
|
|
|
|
report_context = {
|
|
|
|
'company': self.start.company.id,
|
|
|
|
'start_date': self.start.start_date,
|
|
|
|
'end_date': self.start.end_date,
|
|
|
|
'shop': shop_id,
|
|
|
|
}
|
|
|
|
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
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
report_context = super(SaleByKindReport, cls).get_context(records, data)
|
|
|
|
pool = Pool()
|
|
|
|
Sale = pool.get('sale.sale')
|
|
|
|
Company = pool.get('company.company')
|
|
|
|
company = Company(data['company'])
|
|
|
|
|
|
|
|
dom = [
|
|
|
|
('company', '=', company),
|
|
|
|
('sale_date', '>=', data['start_date']),
|
|
|
|
('sale_date', '<=', data['end_date']),
|
2020-12-28 04:21:31 +01:00
|
|
|
('state', 'in', ('done', 'processing')),
|
|
|
|
|
2020-12-28 03:32:05 +01:00
|
|
|
]
|
|
|
|
if data['shop']:
|
|
|
|
dom.append(('shop', '=', data['shop']))
|
|
|
|
|
|
|
|
records = {}
|
|
|
|
sales = Sale.search(dom)
|
|
|
|
for sale in sales:
|
|
|
|
if sale.kind:
|
|
|
|
kind = sale.kind
|
|
|
|
else:
|
2020-12-28 04:21:31 +01:00
|
|
|
kind = 'others'
|
2020-12-28 03:32:05 +01:00
|
|
|
if sale.shop:
|
|
|
|
shop = sale.shop.name
|
|
|
|
else:
|
2020-12-28 04:21:31 +01:00
|
|
|
shop = 'others'
|
2020-12-28 03:32:05 +01:00
|
|
|
shop_id = str(shop)
|
|
|
|
amount_cache = sale.total_amount_cache
|
|
|
|
if shop_id not in records:
|
|
|
|
records[shop_id] = {
|
|
|
|
'shop': shop,
|
2020-12-28 04:21:31 +01:00
|
|
|
'kind_others': [],
|
2020-12-28 03:32:05 +01:00
|
|
|
'kind_to_table': [],
|
|
|
|
'kind_delivery': [],
|
|
|
|
'kind_take_away': [],
|
2020-12-30 00:14:00 +01:00
|
|
|
'sale_amount': []
|
2020-12-28 03:32:05 +01:00
|
|
|
}
|
2020-12-28 04:21:31 +01:00
|
|
|
if kind == 'others':
|
|
|
|
records[shop_id]['kind_others'].append(amount_cache)
|
|
|
|
elif kind == 'to_table':
|
|
|
|
records[shop_id]['kind_to_table'].append(amount_cache)
|
|
|
|
elif kind == 'delivery':
|
|
|
|
records[shop_id]['kind_delivery'].append(amount_cache)
|
|
|
|
elif kind == 'take_away':
|
|
|
|
records[shop_id]['kind_take_away'].append(amount_cache)
|
|
|
|
records[shop_id]["sale_amount"].append(amount_cache)
|
|
|
|
total_amount = 0
|
|
|
|
total_amount_delivery = 0
|
|
|
|
total_amount_others = 0
|
|
|
|
total_amount_take_away = 0
|
|
|
|
total_amount_to_table = 0
|
|
|
|
total_sales = 0
|
|
|
|
total_sales_delivery = 0
|
|
|
|
total_sales_others = 0
|
|
|
|
total_sales_take_away = 0
|
|
|
|
total_sales_to_table = 0
|
2020-12-28 03:32:05 +01:00
|
|
|
for r in records.values():
|
2020-12-28 04:21:31 +01:00
|
|
|
total_amount_others += sum(r['kind_others'])
|
|
|
|
total_sales_others += len(r['kind_others'])
|
2020-12-28 03:32:05 +01:00
|
|
|
total_amount_to_table += sum(r['kind_to_table'])
|
|
|
|
total_sales_to_table += len(r['kind_to_table'])
|
|
|
|
total_amount_delivery += sum(r['kind_delivery'])
|
|
|
|
total_sales_delivery += len(r['kind_delivery'])
|
|
|
|
total_amount_take_away += sum(r['kind_take_away'])
|
|
|
|
total_sales_take_away += len(r['kind_take_away'])
|
|
|
|
total_amount += sum(r['sale_amount'])
|
|
|
|
total_sales += len(r['sale_amount'])
|
|
|
|
|
|
|
|
report_context['records'] = records.values()
|
|
|
|
report_context['company'] = company.rec_name
|
2020-12-28 04:21:31 +01:00
|
|
|
report_context['total_amount_others'] = total_amount_others
|
|
|
|
report_context['total_sales_others'] = total_sales_others
|
2020-12-28 03:32:05 +01:00
|
|
|
report_context['total_amount_delivery'] = total_amount_delivery
|
|
|
|
report_context['total_sales_delivery'] = total_sales_delivery
|
|
|
|
report_context['total_amount_take_away'] = total_amount_take_away
|
|
|
|
report_context['total_sales_take_away'] = total_sales_take_away
|
|
|
|
report_context['total_amount_to_table'] = total_amount_to_table
|
|
|
|
report_context['total_sales_to_table'] = total_sales_to_table
|
|
|
|
report_context['total_amount'] = total_amount
|
|
|
|
report_context['total_sales'] = total_sales
|
|
|
|
report_context['data'] = data
|
|
|
|
return report_context
|
|
|
|
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_company():
|
|
|
|
return Transaction().context.get('company')
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def default_start_date():
|
|
|
|
today_ = date.today()
|
|
|
|
month = today_.month
|
|
|
|
day = today_.day
|
|
|
|
year = today_.year
|
|
|
|
if month == 1:
|
|
|
|
old_month = 12
|
|
|
|
else:
|
|
|
|
old_month = month - 1
|
|
|
|
return date(year, old_month, day)
|
|
|
|
|
|
|
|
@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,
|
|
|
|
}
|
|
|
|
if self.start.user:
|
|
|
|
data['user'] = self.start.user.id
|
|
|
|
return action, data
|
|
|
|
|
|
|
|
def transition_print_(self):
|
|
|
|
return 'end'
|
|
|
|
|
|
|
|
|
|
|
|
class PortfolioPaymentsReport(Report):
|
|
|
|
'Portfolio Payments Report'
|
|
|
|
__name__ = 'sale_pos.portfolio_payments_report'
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_context(cls, records, data):
|
|
|
|
report_context = super(PortfolioPaymentsReport, cls).get_context(
|
|
|
|
records, data)
|
|
|
|
pool = Pool()
|
|
|
|
VoucherLine = pool.get('account.voucher.line')
|
|
|
|
today = date.today()
|
|
|
|
dom_search = [
|
|
|
|
('voucher.date', '>=', data['start_date']),
|
|
|
|
('voucher.date', '<=', data['end_date']),
|
|
|
|
('voucher.company', '=', data['company']),
|
|
|
|
('voucher.state', 'not in', ['cancel', 'draft']),
|
|
|
|
]
|
|
|
|
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
|
|
|
|
origin = move_line.origin
|
|
|
|
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 ''
|
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 = ''
|
|
|
|
number = move_line.reference
|
|
|
|
invoice_date = ''
|
|
|
|
invoice_amount = move_line.amount
|
|
|
|
invoice_balance = None
|
|
|
|
|
|
|
|
voucher_lines.append({
|
|
|
|
'number': voucher.number,
|
|
|
|
'shop': shop,
|
|
|
|
'salesman': salesman,
|
|
|
|
'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,
|
|
|
|
'state': voucher.state_string
|
|
|
|
})
|
|
|
|
|
|
|
|
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
|