trytondo-sale_payment/statement.py

371 lines
13 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 trytond.model import fields, ModelView
from trytond.pool import Pool, PoolMeta
from trytond.transaction import Transaction
from trytond.wizard import Button, StateTransition, StateView, Wizard
from decimal import Decimal
from trytond.i18n import gettext
from trytond.modules.currency.fields import Monetary
from trytond.pyson import Eval
from trytond.exceptions import UserError
from datetime import datetime
__all__ = ['Journal', 'Statement', 'Line', 'OpenStatementStart',
'OpenStatementDone', 'OpenStatement', 'CloseStatementStart',
'CloseStatementDone', 'CloseStatement']
class Journal(metaclass=PoolMeta):
__name__ = 'account.statement.journal'
devices = fields.One2Many('sale.device', 'journal', 'Devices')
class Statement(metaclass=PoolMeta):
__name__ = 'account.statement'
users = fields.Function(fields.One2Many('res.user', None, 'Users'),
'get_users', searcher='search_users')
@classmethod
def get_users(cls, statements, names):
return {'users': {s.id: [u.id
for j in s.journal
for d in j.devices
for u in d.users
]
} for s in statements}
@classmethod
def search_users(cls, name, clause):
pool = Pool()
Journal = pool.get('account.statement.journal')
Device = pool.get('sale.device')
DeviceJournal = pool.get('sale.device.account.statement.journal')
User = pool.get('res.user')
statement = cls.__table__()
journal = Journal.__table__()
device = Device.__table__()
device_journal = DeviceJournal.__table__()
user = User.__table__()
query = statement.join(
journal, condition=statement.journal == journal.id).join(
device_journal,
condition=journal.id == device_journal.journal).join(
device, condition=device_journal.device == device.id).join(
user, condition=device.id == user.sale_device).select(
statement.id,
where=user.id == clause[2])
return [('id', 'in', query)]
class Line(metaclass=PoolMeta):
__name__ = 'account.statement.line'
sale = fields.Many2One('sale.sale', 'Sale', ondelete='RESTRICT')
def create_move(self):
'''
Create move for the statement line and return move if created.
Redefined method to allow amounts in statement lines greater than the
invoice amount.
'''
pool = Pool()
Move = pool.get('account.move')
Period = pool.get('account.period')
Invoice = pool.get('account.invoice')
Currency = pool.get('currency.currency')
MoveLine = pool.get('account.move.line')
if self.move:
return
period_id = Period.find(self.statement.company.id, date=self.date)
move_lines = self._get_move_lines()
move = Move(
period=period_id,
journal=self.statement.journal.journal,
date=self.date,
origin=self,
lines=move_lines,
)
move.save()
self.write([self], {
'move': move.id,
})
if self.invoice:
with Transaction().set_context(date=self.invoice.currency_date):
amount = Currency.compute(self.statement.journal.currency,
self.amount, self.statement.company.currency)
reconcile_lines = self.invoice.get_reconcile_lines_for_amount(
abs(amount))
for move_line in move.lines:
if move_line.account == self.invoice.account:
Invoice.write([self.invoice], {
'payment_lines': [('add', [move_line.id])],
})
break
if reconcile_lines[1] == Decimal('0.0'):
lines = reconcile_lines[0] + [move_line]
MoveLine.reconcile(lines)
return move
class OpenStatementStart(ModelView):
'Open Statement'
__name__ = 'open.statement.start'
class OpenStatementDone(ModelView):
'Open Statement'
__name__ = 'open.statement.done'
result = fields.Text('Result', readonly=True)
class OpenStatement(Wizard):
'Open Statement'
__name__ = 'open.statement'
start = StateView('open.statement.start',
'sale_payment.open_statement_start', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'create_', 'tryton-ok', default=True),
])
create_ = StateTransition()
done = StateView('open.statement.done',
'sale_payment.open_statement_done', [
Button('Done', 'end', 'tryton-ok', default=True),
])
def default_done(self, fields):
return {
'result': self.result,
}
def transition_create_(self):
pool = Pool()
User = pool.get('res.user')
Statement = pool.get('account.statement')
user = Transaction().user
user = User(user)
device = user.sale_device
if device:
journals = [j.id for j in device.journals]
statements = Statement.search([
('journal', 'in', journals),
], order=[
('date', 'ASC'),
])
journals_of_draft_statements = [s.journal for s in statements
if s.state == 'draft']
start_balances = {
s.journal.id: s.end_balance or Decimal('0.0')
for s in statements
}
vlist = []
results = []
for journal in device.journals:
if journal not in journals_of_draft_statements:
values = {
'name': '%s - %s' % (device.rec_name, journal.rec_name),
'journal': journal.id,
'company': user.company.id,
'start_balance': start_balances.get(journal.id,
Decimal('0.0')),
'end_balance': Decimal('0.0'),
'total_amount': Decimal('0.0'),
'number_of_lines': 0,
}
vlist.append(values)
results.append(gettext('sale_payment.open_statement',
statement=journal.rec_name))
else:
results.append(gettext('sale_payment.statement_already_opened',
statement=journal.rec_name))
statements.extend(Statement.create(vlist))
self.result = '\n'.join(results)
else:
self.result = gettext('sale_payment.user_without_device',
user=user.rec_name)
return 'done'
class CloseStatementStart(ModelView):
'Close Statement'
__name__ = 'close.statement.start'
statementLines = fields.One2Many('statement.line', None, 'Lines')
class CloseStatementDone(ModelView):
'Close Statement'
__name__ = 'close.statement.done'
result = fields.Text('Result', readonly=True)
class CloseStatement(Wizard):
'Close Statement'
__name__ = 'close.statement'
start = StateView('close.statement.start',
'sale_payment.close_statement_start', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'validate', 'tryton-ok', default=True),
])
validate = StateTransition()
done = StateView('close.statement.done',
'sale_payment.close_statement_done', [
Button('Done', 'end', 'tryton-ok', default=True),
])
def default_done(self, fields):
return {
'result': self.result,
}
def default_start(self, fields):
pool = Pool()
User = pool.get('res.user')
StatementLine = pool.get('statement.line')
Statement = pool.get('account.statement')
statementLines = []
user = Transaction().user
user = User(user)
device = user.sale_device
if device:
journals = [j.id for j in device.journals]
draft_statements = {
s.journal: s for s in Statement.search([
('journal', 'in', journals),
], order=[
('create_date', 'ASC'),
])}
for s in draft_statements.values():
end_balance = Decimal('0.0')
for line in s.lines:
end_balance += line.amount
line = {
'journal': s.journal.id,
'start_balance': s.start_balance,
'balance': end_balance,
'end_balance':end_balance+s.start_balance
}
statementLines.append(line)
default = {'statementLines': statementLines}
return default
def transition_validate(self):
pool = Pool()
User = pool.get('res.user')
Statement = pool.get('account.statement')
StatementLine = pool.get('account.statement.line')
user = Transaction().user
user = User(user)
device = user.sale_device
if device:
journals = [j.id for j in device.journals]
draft_statements = {
s.journal: s for s in Statement.search([
('journal', 'in', journals),
], order=[
('create_date', 'ASC'),
])}
results = []
statements = []
#raise UserError(str((device.journals)))
#raise UserError(str((self.start.statementLines[0].journal)))
for journal in self.start.statementLines:
account = journal.account
transfer = journal.transfer
end_balance = journal.end_balance
journal = journal.journal
statement = draft_statements.get(journal)
if statement and statement.state == 'draft':
if not statement.start_balance:
statement.start_balance = Decimal(0)
if account and transfer:
end_balance = abs(end_balance) - abs(transfer)
statement.end_balance = end_balance
lines = statement.lines
conciliation = tuple([StatementLine(
date=datetime.today().date(),
amount= abs(transfer)*-1,
account=account.id)]
)
#raise UserError(str(conciliation))
statement.lines = statement.lines + conciliation
else:
end_balance = statement.start_balance
for line in statement.lines:
end_balance += line.amount
statement.end_balance = end_balance
statement.save()
statements.append(statement)
results.append(gettext('sale_payment.close_statement',
statement=statement.rec_name))
elif statement:
results.append(gettext('sale_payment.statement_already_closed',
statement=statement.rec_name))
else:
results.append(gettext('sale_payment.not_statement_found',
journal=journal.rec_name))
if statements:
Statement.validate_statement(statements)
self.result = '\n'.join(results)
else:
self.result = gettext('sale_payment.user_without_device',
user=user.rec_name)
return 'done'
class StatementLine(ModelView):
"statement Line"
__name__ = 'statement.line'
company = fields.Many2One(
'company.company', "Company", required=True, select=True)
journal = fields.Many2One('account.statement.journal', 'Journal',
required=True, select=True)
currency = fields.Many2One(
'currency.currency', "Currency")
start_balance = Monetary(
"Start Balance", currency='currency', digits='currency')
balance = Monetary(
"Balance", currency='currency', digits='currency')
transfer = Monetary(
"Transfer", currency='currency', digits='currency')
end_balance = Monetary(
"End Balance", currency='currency', digits='currency')
account = fields.Many2One(
'account.account', "Account",
domain=[
('company', '=', Eval('company', 0)),
('type', '!=', None),
('closed', '!=', True),
])
@staticmethod
def default_currency():
Company = Pool().get('company.company')
company = Transaction().context.get('company')
if company:
return Company(company).currency.id
@staticmethod
def default_company():
return Transaction().context.get('company')