trytonpsk-hotel/sale.py

361 lines
13 KiB
Python

# This file is part of Presik. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from datetime import datetime, date
from decimal import Decimal
from trytond.i18n import gettext
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
from trytond.report import Report
from trytond.model import ModelView, fields
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.wizard import (
Wizard, StateView, Button, StateReport, StateTransition)
_ZERO = Decimal(0)
class Sale(metaclass=PoolMeta):
__name__ = 'sale.sale'
# folio = fields.Many2One('hotel.folio', 'Folio', states={
# 'readonly': True,
# })
@classmethod
def __setup__(cls):
super(Sale, cls).__setup__()
# _states = {
# 'readonly': Eval('state') != 'draft',
# }
cls.state.selection.append(('transferred', 'Transferred'))
@classmethod
def transfer_to_folio(cls, sale_id, folio_id):
sale, = cls.browse([sale_id])
Charge = Pool().get('hotel.folio.charge')
Folio = Pool().get('hotel.folio')
to_create = []
folio = Folio(folio_id)
number = sale.number
if folio.charges_blocked:
raise UserError(gettext('hotel.msg_folio_charges_blocked'))
if folio.registration_state == 'check_out':
raise UserError(gettext('hotel.msg_folio_closed'))
for line in sale.lines:
unit_price = line.unit_price.quantize(Decimal('.01'))
to_create.append({
'folio': folio_id,
'product': line.product.id,
'description': line.description,
'quantity': line.quantity,
'date_service': line.sale.sale_date,
'unit_price': unit_price,
'kind': 'product',
'order': number,
'status': 'pending',
'origin': f'sale.line,{line.id}',
})
charges_ids = Charge.create(to_create)
# 'folio': folio_id,
cls.write([sale], {
'state': 'transferred',
'invoice_method': 'manual',
'shipment_method': 'manual',
'reference': folio.booking.number,
})
# FIXME: Add stock moves
return 'ok'
@classmethod
def transfer_to_sale(cls, sale_id, target_sale_id):
Line = Pool().get('sale.line')
sale, = cls.browse([sale_id])
target, = cls.browse([target_sale_id])
for line in sale.lines:
nwline, = Line.copy([line])
nwline.sale = target.id
nwline.origin = f'sale.line,{line.id}'
nwline.save()
cls.write([sale], {
'state': 'transferred',
'invoice_method': 'manual',
'shipment_method': 'manual',
'reference': sale.number,
})
# FIXME: Add stock moves
return 'ok'
class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line'
origin = fields.Reference('Origin', selection='get_origin', readonly=True)
@classmethod
def _get_origin(cls):
'Return list of Model names for origin Reference'
return ['sale.line']
@classmethod
def get_origin(cls):
Model = Pool().get('ir.model')
get_name = Model.get_name
models = cls._get_origin()
return [(None, '')] + [(m, get_name(m)) for m in models]
class InvoiceIncomeDailyStart(ModelView):
'Invoice Income Daily Start'
__name__ = 'hotel.invoice_income_daily.start'
company = fields.Many2One('company.company', 'Company', required=True)
invoice_date = fields.Date('Invoice Date', required=True)
user = fields.Many2One('res.user', 'User', required=True)
shop = fields.Many2One('sale.shop', 'Shop', required=True)
# journal = fields.Many2One('account.statement.journal', 'Journal')
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_sale_date():
Date = Pool().get('ir.date')
return Date.today()
class InvoiceIncomeDaily(Wizard):
'Invoice Income Daily'
__name__ = 'hotel.invoice_income_daily'
start = StateView(
'hotel.invoice_income_daily.start',
'hotel.invoice_income_daily_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('hotel.invoice_income_daily_report')
def do_print_(self, action):
report_context = {
'company': self.start.company.id,
'invoice_date': self.start.invoice_date,
'user': self.start.user.id,
'shop': self.start.shop.id,
}
return action, report_context
def transition_print_(self):
return 'end'
class InvoiceIncomeDailyReport(Report):
'Invoice Income Daily Report'
__name__ = 'hotel.invoice_income_daily_report'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Invoice = pool.get('account.invoice')
Company = pool.get('company.company')
company = Company(data['company'])
Statement = pool.get('account.statement')
Shop = pool.get('sale.shop')
User = pool.get('res.user')
shop = Shop(data['shop'])
statements = Statement.search([
('date', '=', data['invoice_date']),
('create_uid', '=', data['user']),
])
user = User(data['user'])
records = []
advances = []
statements_ = []
total_advances = []
advances_cash = []
advances_electronic = []
total_statements = []
for statement in statements:
st_amount = sum(li.amount for li in statement.lines)
statements_.append({
'id': statement.id,
'sale_device': statement.sale_device.name,
'journal': statement.journal.name,
'turn': statement.turn,
'total_amount': st_amount,
'state': statement.state,
})
total_statements.append(st_amount)
for li in statement.lines:
sale = li.sale
cash = 0
electronic = 0
if sale and not sale.invoice_number:
for pline in sale.payments:
if pline.statement.journal.kind == 'cash':
advances_cash.append(pline.amount)
cash = pline.amount
else:
electronic = pline.amount
advances_electronic.append(pline.amount)
advances.append({
'number': sale.number,
'reference': sale.reference,
'party': sale.party.name,
'total_amount': pline.amount,
'cash': cash,
'electronic': electronic,
})
total_advances.append(pline.amount)
dom_ = [
('company', '=', data['company']),
('invoice_date', '=', data['invoice_date']),
('shop', '=', data['shop']),
('number', '!=', None),
('state', 'in', ['posted', 'paid', 'canceled']),
('create_uid', '=', data['user']),
]
invoices = Invoice.search(dom_, order=[('number', 'ASC')])
invoices_number = []
total_invoices_cash = []
total_invoices_electronic = []
total_invoices_credit = []
total_invoices_paid = []
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]
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['invoice_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)
inv = {
'number': invoice.number,
'reference': invoice.reference,
'party': invoice.party.name,
'total_amount': invoice.total_amount,
'credit': credit,
'cash': cash,
'electronic': electronic,
'paid': cash + electronic,
'state': invoice.state_string,
}
records.append(inv)
report_context['records'] = records
report_context['advances'] = advances
report_context['statements'] = statements_
report_context['date'] = data['invoice_date']
report_context['company'] = company
report_context['shop'] = shop.name
report_context['user'] = user.name
report_context['print_date'] = datetime.now()
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'] = sum(advances_cash)
report_context['advances_electronic'] = sum(advances_electronic)
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 ''
return report_context
class InvoiceSimplifiedReport(Report):
__name__ = 'account.invoice_simplified'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
Company = Pool().get('company.company')
categories = {}
if records:
record = records[0]
for l in record.lines:
cat = l.product.template.account_category
taxes = ''
for tax in cat.customer_taxes_used:
taxes += tax.name + ' '
if cat.id not in categories.keys():
categories[cat.id] = {
'description': cat.name,
'amount': l.amount,
'taxes': taxes
}
else:
categories[cat.id]['amount'] += l.amount
record._lines = categories.values()
report_context['company'] = Company(Transaction().context['company'])
return report_context
class SaleTransferStart(ModelView):
'Sale Transfer Start'
__name__ = 'sale.transfer.start'
kind = fields.Selection([
('folio', 'Folio'),
('sale', 'Sale'),
], 'Kind', required=True)
folio = fields.Many2One('hotel.folio', 'Folio', domain=[
('registration_state', '=', 'check_in'),
('arrival_date', '<=', date.today()),
('departure_date', '>=', date.today()),
], states={
'invisible': Eval('kind') != 'folio'
})
sale = fields.Many2One('sale.sale', 'Sale', domain=[
('state', '=', 'draft'),
('number', '!=', None),
], states={
'invisible': Eval('kind') != 'sale'
})
class SaleTransfer(Wizard):
'Sale Transfer'
__name__ = 'sale.transfer'
start = StateView(
'sale.transfer.start',
'hotel.sale_transfer_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'accept', 'tryton-ok', default=True),
])
accept = StateTransition()
def transition_accept(self):
Sale = Pool().get('sale.sale')
sale_id = Transaction().context['active_id']
if self.start.kind == 'folio':
Sale.transfer_to_folio(sale_id, self.start.folio.id)
else:
Sale.transfer_to_sale(sale_id, self.start.sale.id)
return 'end'