trytondo-sale_payment_form/sale.py

194 lines
6.8 KiB
Python

# This file is part of the sale_payment module for Tryton.
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from decimal import Decimal
from sql.aggregate import Sum
from sql.conditionals import Coalesce
from trytond.model import ModelView, fields
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Bool, Eval, Not
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, StateTransition, Button
from trytond.i18n import gettext
from trytond.exceptions import UserError
class SalePaymentForm(metaclass=PoolMeta):
'Sale Payment Form'
__name__ = 'sale.payment.form'
received_amount = fields.Numeric('Received amount', required=True,
digits=(16, Eval('currency_digits',2)),
depends=['currency_digits'])
change_amount = fields.Numeric('Change amount', readonly=True,
digits=(16, Eval('currency_digits',2)),
depends=['currency_digits'])
@fields.depends('payment_amount', 'received_amount')
def on_change_received_amount(self):
pool = Pool()
Sale = pool.get('sale.sale')
sale = Sale(Transaction().context['active_id'])
amount = sale.total_amount - sale.paid_amount
if self.payment_amount < 0:
self.received_amount = self.payment_amount
self.change_amount = 0
else:
if self.received_amount < 0:
self.received_amount = None
self.payment_amount = amount
self.change_amount = 0
elif self.received_amount < amount:
self.payment_amount = self.received_amount
self.change_amount = 0
else:
self.payment_amount = amount
self.change_amount = self.received_amount - self.payment_amount
@fields.depends('payment_amount', 'received_amount')
def on_change_payment_amount(self):
pool = Pool()
Sale = pool.get('sale.sale')
sale = Sale(Transaction().context['active_id'])
amount = sale.total_amount - sale.paid_amount
if self.payment_amount < 0:
self.payment_amount = amount
self.received_amount = amount
if self.received_amount:
if self.payment_amount > self.received_amount:
self.payment_amount = self.received_amount
self.change_amount = self.received_amount - self.payment_amount
if self.payment_amount > amount:
self.payment_amount = amount
class WizardSalePayment(metaclass=PoolMeta):
'Wizard Sale Payment'
__name__ = 'sale.payment'
start = StateView('sale.payment.form',
'sale_payment.sale_payment_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Pay', 'pay_', 'tryton-ok', default=True),
])
pay_ = StateTransition()
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:
raise UserError(gettext('sale_payment.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 get_statement_line(self, sale):
pool = Pool()
Date = pool.get('ir.date')
Sale = pool.get('sale.sale')
Statement = pool.get('account.statement')
StatementLine = pool.get('account.statement.line')
form = self.start
statements = Statement.search([
('journal', '=', form.journal),
('state', '=', 'draft'),
], order=[('date', 'DESC')])
if not statements:
raise UserError(gettext('sale_payment.not_draft_statement',
journal=form.journal.name))
if not sale.number:
Sale.set_number([sale])
with Transaction().set_context(date=Date.today()):
account = sale.party.account_receivable_used
if not account:
raise UserError(gettext(
'sale_payment.party_without_account_receivable',
party=sale.party.name))
if form.payment_amount:
return StatementLine(
statement=statements[0],
date=Date.today(),
amount=form.payment_amount,
party=sale.party,
invoice=sale.invoices[0].id if sale.invoices else None,
account=account,
description=sale.number,
sale=sale,
)
def transition_pay_(self):
Sale = Pool().get('sale.sale')
active_id = Transaction().context.get('active_id', False)
sale = Sale(active_id)
if sale.state != 'draft':
line = self.get_statement_line(sale)
if line:
line.save()
return 'end'
else:
sale.description = sale.reference
sale.save()
Sale.workflow_to_end([sale])
line = self.get_statement_line(sale)
if line:
line.save()
if sale.total_amount != sale.paid_amount:
return 'start'
return 'end'
class WizardSaleReconcile(Wizard):
'Reconcile Sales'
__name__ = 'sale.reconcile'
start = StateTransition()
reconcile = StateTransition()
def transition_start(self):
pool = Pool()
Sale = pool.get('sale.sale')
Line = pool.get('account.move.line')
for sale in Sale.browse(Transaction().context['active_ids']):
account = sale.party.account_receivable_used
lines = []
amount = Decimal('0.0')
for invoice in sale.invoices:
for line in invoice.lines_to_pay:
if not line.reconciliation:
lines.append(line)
amount += line.debit - line.credit
for payment in sale.payments:
if not payment.move:
continue
for line in payment.move.lines:
if (not line.reconciliation and
line.account.id == account.id):
lines.append(line)
amount += line.debit - line.credit
if lines and amount == Decimal('0.0'):
Line.reconcile(lines)
return 'end'