trytonpsk-laboratory/service_order.py

1093 lines
40 KiB
Python
Executable File

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from datetime import date
from decimal import Decimal
from trytond.model import Workflow, ModelView, ModelSQL, DeactivableMixin, fields
from trytond.pyson import Eval, If, In, Get, Bool, Id
from trytond.transaction import Transaction
from trytond.pool import Pool, PoolMeta
from trytond.wizard import Wizard, StateReport, StateTransition, StateView, Button
from trytond.report import Report
from trytond.exceptions import UserError
from trytond.modules.company.model import employee_field
from trytond.modules.product import round_price
# from trytond.i18n import gettext
# from .exceptions import ValidatePaymentTermParty
STATES = {
'readonly': Eval('state') != 'draft',
}
STATES_OPEN = {
'readonly': Eval('state') != 'reception',
'required': Eval('state') == 'finished',
}
STATES_CLOSE = {
'readonly': Eval('state') != 'reception',
'required': Eval('state') == 'finished',
}
LINE_STATES = {
'readonly': ~Eval('order_state').in_(['draft', None])
}
class Order(Workflow, ModelSQL, ModelView):
'Service Order'
__name__ = 'laboratory.order'
_rec_name = 'number'
number = fields.Char('Number', readonly=True)
reference = fields.Char('Reference', states=STATES)
customer = fields.Many2One('party.party', 'Customer', required=True,
states=STATES, select=True)
patient = fields.Many2One('party.party', 'Patient', states=STATES)
doctor = fields.Many2One('party.party', 'Doctor', domain=[
('categories', '=', Eval('doctor_category'))
], depends=['doctor_category'])
request_type = fields.Selection([
('assistential', 'Assistential'),
('extramural', 'Extra-mural'),
('', ''),
], 'Request Type')
description = fields.Char('Description', states=STATES)
order_date = fields.Date('Order Date', required=True, states=STATES)
copago = fields.Numeric('Copago')
cuota_moderadora = fields.Numeric('Cuota Moderadora')
delivery = fields.Numeric('Delivery Amount', states=STATES)
discount_amount = fields.Numeric('Discount Amount', states=STATES)
discount_rate = fields.Function(fields.Numeric(
"Discount Rate", digits=(16, 2),
states={
'readonly': Eval('state') != 'draft',
},
depends=['state']),
'on_change_with_discount_rate', setter='set_discount_rate')
received_by = employee_field("Received By")
company = fields.Many2One(
'company.company', 'Company', required=True,
states=STATES,
domain=[('id', If(
In('company', Eval('context', {})), '=', '!='),
Get(Eval('context', {}), 'company', 0))
])
state = fields.Selection([
('draft', 'Draft'),
('processed', 'Processed'),
('invoiced', 'Invoiced'),
('paid', 'Paid'),
('cancelled', 'Cancelled'),
], 'State', readonly=True, required=True)
invoice_type = fields.Selection([
('P', 'POS'),
('M', 'Manual'),
('91', 'Nota Crédito Eléctronica'),
('1', 'Venta Electronica'),
], 'Invoice Type')
method_process = fields.Selection([
('courtesy', 'Courtesy'),
('intern', 'Intern'),
('invoice', 'Invoice'),
('delivery', 'Delivery'),
], 'Method Process')
state_string = state.translated('state')
status_invoice = fields.Selection([
('without_invoice', 'Without Invoice'),
('partial_invoice', 'Partial Invoice'),
('invoiced', 'Invoiced'),
], 'Status Invoice', readonly=True, required=True)
state_string = state.translated('state')
price_list = fields.Many2One('product.price_list', 'Price List',
states=STATES)
lines = fields.One2Many('laboratory.order.line', 'order',
'Lines', states=STATES)
comment = fields.Text('Comment', states=STATES)
payment_term = fields.Many2One('account.invoice.payment_term',
'Payment Term', states=STATES, depends=['state'])
copago_invoice = fields.Many2One('account.invoice',
'Copago Invoice', states=STATES, depends=['state'])
copago_invoice_state = fields.Function(fields.Char(
'Copago Invoice State'), 'get_invoice_state')
invoice = fields.Many2One('account.invoice', 'Invoice', states=STATES,
depends=['state'])
invoice_state = fields.Function(fields.Char(
'Invoice State'), 'get_invoice_state')
doctor_category = fields.Function(fields.Many2One('party.category', 'Doctor Category'),
'get_doctor_category')
operation_center = fields.Many2One('company.operation_center', 'Operation Center',
states=STATES, depends=['state'])
payments = fields.One2Many('laboratory.order.payment', 'order',
'Payments', states=STATES)
total_amount = fields.Function(fields.Numeric('Total Amount',
digits=(16, 2)), 'get_total_amount')
total_neto = fields.Function(fields.Numeric('Total Neto',
digits=(16, 2)), 'get_total_neto')
unidentified_party = fields.Char('Unidentified Party')
unidentified_party_type = fields.Selection([
('AS', 'Unidentified Adult'),
('MS', 'Unidentified Child'),
('', ''),
], 'Unidentified Party Type')
sex = fields.Selection([
('male', 'M'),
('female', 'F'),
('', ''),
], 'Sex')
birthday = fields.Date('Birthday')
@classmethod
def __setup__(cls):
super(Order, cls).__setup__()
cls._order.insert(0, ('create_date', 'DESC'))
cls._order.insert(1, ('id', 'DESC'))
cls._transitions |= set((
('draft', 'processed'),
('processed', 'invoiced'),
('processed', 'paid'),
('invoiced', 'paid'),
))
cls._buttons.update({
'draft': {
'invisible': Eval('state').in_(['draft', 'processed'])
},
'cancel': {
'invisible': Eval('state').in_(['cancelled', 'draft', 'processed']),
},
'process': {
'invisible': Eval('state') != 'draft',
},
'process_einvoice': {
'invisible': Eval('state') != 'processed',
},
'reconcile': {
'invisible': ~Eval('state').in_(['processed','invoiced'])
},
})
@staticmethod
def default_company():
return Transaction().context.get('company') or False
@staticmethod
def default_state():
return 'draft'
@staticmethod
def default_method_process():
return 'invoice'
@staticmethod
def default_invoice_type():
return '1'
@staticmethod
def default_status_invoice():
return 'without_invoice'
@staticmethod
def default_order_date():
Date = Pool().get('ir.date')
return Date.today()
@staticmethod
def default_operation_center():
Op_center = Pool().get('company.operation_center')
op_centers = Op_center.search([])
if len(op_centers) == 1:
return op_centers[0].id
@classmethod
def copy(cls, orders, default=None):
if default is None:
default = {}
default = default.copy()
default.setdefault('payments', None)
return super().copy(orders, default=default)
@classmethod
def create(cls, vlist):
return super(Order, cls).create(vlist)
@classmethod
@ModelView.button
@Workflow.transition('processed')
def process(cls, records):
for rec in records:
rec.set_number()
transaction = Transaction()
if rec.method_process in ('invoice', 'delivery'):
with transaction.set_context(_skip_warnings=True):
cls.execute_processing(rec)
@classmethod
@ModelView.button
# @Workflow.transition('invoiced')
def process_einvoice(cls, records):
for rec in records:
transaction = Transaction()
with transaction.set_context(_skip_warnings=True):
cls.execute_processing_invoice(rec)
if rec.customer.sale_invoice_grouping_method != 'standard':
rec.state = 'invoiced'
rec.save()
@classmethod
@ModelView.button
@Workflow.transition('cancelled')
def cancel(cls, records):
pass
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, records):
pass
@classmethod
@ModelView.button
def reconcile(cls, records):
for record in records:
cls.reconcile_order(record)
@classmethod
def delete(cls, records):
for record in records:
if record.number:
raise UserError('delete_numbered')
super(Order, cls).delete(records)
@classmethod
def execute_processing(cls, args):
print('......execute_....')
record = args
pool = Pool()
Invoice = pool.get('account.invoice')
configuration = pool.get('laboratory.configuration')(1)
invoices = Invoice.search(['reference', '=', record.number])
if invoices and (not record.invoice or not record.copago_invoice):
if record.copago:
record.copago_invoice = invoices[0]
else:
record.invoice = invoices[0]
record.save()
if not record.invoice and not record.copago_invoice:
invoice = record.create_invoice()
Invoice = Pool().get('account.invoice')
if invoice and invoice.state == 'draft' and configuration.validate_invoice:
Invoice.validate_invoice([invoice])
@classmethod
def execute_processing_invoice(cls, record):
transaction = Transaction()
with transaction.set_context(_skip_warnings=True):
invoice = record.invoice or record.copago_invoice
if invoice:
record.process_invoice(invoice)
if record.payments:
record.process_payment()
if invoice and record.payments:
cls.reconcile_order(record)
def get_invoice_state(self, name=None):
if name == 'copago_invoice_state' and self.copago_invoice:
return self.copago_invoice.state_string
if name == 'invoice_state' and self.invoice:
return self.invoice.state_string
def get_doctor_category(self, name=None):
Config = Pool().get('laboratory.configuration')
config = Config.get_configuration()
return config.doctor_category.id if config.doctor_category else None
def get_total_amount(self, name=None):
res = []
for line in self.lines:
res.append(line.unit_price * Decimal(line.quantity))
return sum(res)
def get_total_neto(self, name=None):
if self.total_amount:
discount_amount = self.discount_amount if self.discount_amount else 0
return self.total_amount - discount_amount
@classmethod
def reconcile_order(cls, order):
pool = Pool()
invoice = order.invoice or order.copago_invoice
# to_reconcile
if invoice.state in ('draft', 'validated'):
transaction = Transaction()
with transaction.set_context(_skip_warnings=True):
order.process_invoice(invoice)
elif invoice.state == 'paid':
cls.write([order], {'state': 'paid', 'status_invoice': 'invoiced'})
payments_invoice = [l.id for l in invoice.payment_lines]
to_reconcile = []
if invoice.move:
to_reconcile = [
l.id for l in invoice.move.lines if l.account == invoice.account
]
if order.payments and invoice and invoice.move:
Invoice = pool.get('account.invoice')
Payment = pool.get('laboratory.order.payment')
Reconciliation = pool.get('account.move.reconciliation')
for payment in order.payments:
if not payment.move or (invoice.total_amount < payment.amount):
continue
_lines = [
l.id for l in payment.move.lines if l.account == invoice.account and l.id not in payments_invoice
]
Invoice.write([invoice], {'payment_lines': [('add', _lines)]})
to_reconcile.extend(_lines)
if order.check_to_reconcile(to_reconcile):
Reconciliation.create([{
'lines': [('add', to_reconcile)],
'date': date.today(),
}])
cls.write([order], {'state': 'paid', 'status_invoice': 'invoiced'})
Payment.write(list(order.payments), {'reconciled': True})
if invoice.state == 'posted' and order.discount_amount and len(invoice.charges) < 1\
and order.company.currency.is_zero(invoice.amount_to_pay - order.discount_amount):
order.create_move_to_reconcile(invoice, list(set(to_reconcile + payments_invoice)))
@fields.depends('discount_amount')
def on_change_with_discount_rate(self, name=None):
if self.discount_amount is None:
return
rate = (self.discount_amount / self.total_amount) * 100
return rate
@fields.depends('discount_rate', 'discount_amount', 'total_amount')
def on_change_discount_rate(self):
print(self.discount_rate/100, (self.total_amount * (self.discount_rate/100)))
self.discount_amount = self.total_amount * (self.discount_rate/100)
@classmethod
def set_discount_rate(cls, lines, name, value):
pass
@fields.depends('price_list', 'customer', 'payment_term')
def on_change_customer(self):
if self.customer:
self.price_list = self.customer.sale_price_list
self.payment_term = self.customer.customer_payment_term
@fields.depends('patient', 'unidentified_party')
def on_change_patient(self):
self.unidentified_party = None
def create_move_to_reconcile(self, invoice, lines_to_reconcile):
pool = Pool()
Move = pool.get('account.move')
MoveLine = pool.get('account.move.line')
Period = pool.get('account.period')
Journal = pool.get('account.journal')
Configuration = pool.get('laboratory.configuration')
Reconciliation = pool.get('account.move.reconciliation')
config = Configuration(1)
account = config.account_discount
_date = invoice.invoice_date
period_id = Period.find(self.company.id, date=_date)
journal, = Journal.search([('type', '=', 'general'), ('code', '=', 'GEN')])
if (self.copago or self.copago == 0) or (self.cuota_moderadora or self.cuota_moderadora == 0):
party = self.patient
else:
party = self.customer
_move = {
'journal': journal.id,
'period': period_id,
'date': str(_date),
'state': 'draft',
'description': '',
}
move, = Move.create([_move])
debit = round(self.discount_amount, 2)
lines = [{
'description': self.number,
'account': account.id,
'party': party.id,
'debit': debit,
'credit': Decimal('0.0'),
'move': move.id,
'reference': self.reference,
'operation_center': self.operation_center.id,
}]
credit = debit
line_add = {
'description': self.number,
'party': party.id,
'account': invoice.account.id,
'debit': Decimal('0.0'),
'credit': credit,
'move': move.id,
'reference': self.reference,
}
lines.append(line_add)
MoveLine.create(lines)
Move.post([move])
lines_to_reconcile += [l.id for l in move.lines if l.account.id == invoice.account.id]
if self.check_to_reconcile(lines_to_reconcile):
Reconciliation.create([{
'lines': [('add', lines_to_reconcile)],
'date': date.today(),
}])
self.write([self], {'state': 'paid', 'status_invoice': 'invoiced'})
def check_to_reconcile(self, lines):
MoveLine = Pool().get('account.move.line')
lines = MoveLine.browse(lines)
amount = sum([(line.debit - line.credit) for line in lines])
if self.company.currency.is_zero(amount):
return True
return False
def _create_move_payment(self, payment):
pool = Pool()
Move = pool.get('account.move')
MoveLine = pool.get('account.move.line')
Period = pool.get('account.period')
_date = payment.payment_date
period_id = Period.find(self.company.id, date=_date)
payment_mode = payment.payment_mode
str_origin = 'laboratory.order.payment,' + str(payment.id)
Configuration = pool.get('laboratory.configuration')
config = Configuration(1)
_move = {
'journal': payment_mode.journal.id,
'period': period_id,
'date': str(_date),
'state': 'draft',
'origin': str_origin,
'description': self.description,
}
move, = Move.create([_move])
order = payment.order
debit = round(payment.amount, 2)
lines = [{
'description': order.number,
'account': payment_mode.account.id,
'party': None if config.bill_copago else order.patient.id,
'debit': debit,
'credit': Decimal('0.0'),
'move': move.id,
'reference': order.reference,
'operation_center': order.operation_center.id,
}]
account = None
credit = round(payment.amount, 2)
if order.copago or order.copago == 0:
party = order.patient
account = party.account_receivable_used
if not config.bill_copago:
account = config.advance_accounts
party = order.customer
else:
party = order.customer
account = party.account_receivable_used
line_add = {
'description': order.number,
'party': party.id,
'account': account,
'debit': Decimal('0.0'),
'credit': credit,
'move': move.id,
'reference': order.reference,
}
lines.append(line_add)
_lines = MoveLine.create(lines)
payment.move = move.id
payment.save()
Move.post([move])
return _lines
def process_payment(self):
for pay in self.payments:
if pay.move:
continue
self._create_move_payment(pay)
def process_invoice(self, invoice):
Invoice = Pool().get('account.invoice')
Invoice.process_invoice([invoice])
print('Processed invoice...', invoice.number, invoice.electronic_state)
# if invoice.state == 'draft':
# Invoice.validate_invoice([invoice])
# if invoice.state == 'validated':
# try:
# if invoice.electronic_state != 'authorized':
# Invoice.submit([invoice])
# except Exception as e:
# print('WARNING: Invoice dont sending to DIAN', e)
# try:
# if invoice.invoice_type == 'P' or (
# invoice.electronic_state in ('authorized', 'accepted')
# and invoice.state == 'validated'):
# Invoice.post([invoice])
# except Exception as e:
# print('WARNING: invoice dont posted to DIAN', e)
# self.save()
def set_number(self):
pool = Pool()
Config = pool.get('laboratory.configuration')
if self.number:
return
config = Config.get_configuration()
if not config.laboratory_service_order_sequence:
raise UserError('missing_sequence_service_order')
number = config.laboratory_service_order_sequence.get()
self.write([self], {'number': number})
def get_invoice_authorization(self):
if self.operation_center and self.operation_center.electronic_authorization:
return self.operation_center.electronic_authorization.id
def create_invoice(self):
pool = Pool()
Invoice = pool.get('account.invoice')
Party = pool.get('party.party')
Configuration = pool.get('laboratory.configuration')
config = Configuration(1)
_lines = []
_charges = None
invoice_for_patient = (self.copago or self.copago == 0) or (self.cuota_moderadora or self.cuota_moderadora == 0)
if invoice_for_patient and not config.bill_copago:
return
if invoice_for_patient:
party = self.patient
address = Party.address_get(self.patient, type='invoice')
payment_term = self.payment_term.id
_line = self.get_line_order(type='copago_product')
_lines.append(_line)
operation_type = '10'
else:
operation_type = '10'
party = self.customer
address = Party.address_get(self.customer, type='invoice')
payment_term = self.payment_term.id
# Discount rate
_charges = []
disc_rate = None
discount_amount = self.discount_amount
if discount_amount:
if not config.account_discount or not config.account_courtesy:
raise UserError('missing_account_discount')
total_amount = self.total_amount + (self.delivery if self.delivery else 0)
if discount_amount == total_amount:
account = config.account_courtesy
disc_rate = 100
else:
account = config.account_discount
disc_rate = Decimal(str(round(float(discount_amount / total_amount), 2)))
disc_rate *= 100
_charges += [{
'base_amount': total_amount,
'amount': discount_amount,
'description': 'Descuento comercial',
'charge_percentage': disc_rate,
'charge_concept': '01',
'account': account
}]
for line in self.lines:
_line = self.get_line_order(line=line)
_lines.append(_line)
if party.sale_invoice_grouping_method == 'standard':
return
if self.delivery and self.delivery > 0:
_line = self.get_line_order(type='delivery_product')
_lines.append(_line)
Journal = Pool().get('account.journal')
journals = Journal.search([
('type', '=', 'revenue'),
], limit=1)
journal, = journals
data = {
'operation_type': operation_type,
'company': self.company.id,
'payment_term': payment_term,
'reference': self.number,
'invoice_type': self.invoice_type,
'currency': 31, # FIXME
'party': party.id,
'invoice_date': str(self.order_date),
'state': 'draft',
'authorization': self.get_invoice_authorization(),
'operation_center': self.operation_center.id,
'invoice_address': address.id,
'type': 'out',
'journal': journal.id,
'account': party.account_receivable_used.id,
'lines': [('create', _lines)],
}
if _charges:
data.update({'charges': [('create', _charges)]})
invoice, = Invoice.create([data])
if invoice_for_patient:
self.copago_invoice = invoice.id
self.status_invoice = 'partial_invoice'
self.save()
else:
self.status_invoice = 'invoiced'
self.invoice = invoice.id
self.save()
return invoice
def get_line_order(self, line=None, type=None, discount=None):
pool = Pool()
Configuration = pool.get('laboratory.configuration')
config = Configuration(1)
if type and type == 'copago_product':
if not config.copago_product:
raise UserError('missing_product_copago')
product = config.copago_product
quantity = 1
unit_price = self.copago
elif type and type == 'delivery_product':
if not config.delivery_product:
raise UserError('missing_product_delivey')
product = config.delivery_product
quantity = 1
unit_price = self.delivery
elif line:
product = line.test
quantity = line.quantity
unit_price = line.unit_price
str_origin = None
if line:
str_origin = 'laboratory.order.line,' + str(line.id)
_line = {
'type': 'line',
'operation_center': self.operation_center.id,
'unit': product.template.default_uom.id,
'product': product.id,
'quantity': quantity,
'origin': str_origin,
'unit_price': unit_price,
'description': product.rec_name,
'account': product.template.account_category.account_revenue.id
}
return _line
class CreateInvoiceStart(ModelView):
'laboratory Create Invoice Start'
__name__ = 'laboratory.create_invoice.start'
start_date = fields.Date('Start Date', required=True)
end_date = fields.Date('End Date', required=True)
date_invoice = fields.Date(
'Date of Invoice', help='if has not date, this date will be today')
parties = fields.Many2Many(
'party.party', None, None, 'Parties', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class CreateInvoice(Wizard):
'laboratory Create Invoice'
__name__ = 'laboratory.create_invoice'
start = StateView('laboratory.create_invoice.start',
'laboratory.create_invoice_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Generate', 'generate_',
'tryton-ok', default=True),
])
generate_ = StateTransition()
def transition_generate_(self, add_domain=None):
Order = Pool().get('laboratory.order')
Invoice = Pool().get('account.invoice')
Journal = Pool().get('account.journal')
journal, = Journal.search([('type', '=', 'revenue')], limit=1)
parties = [party.id for party in self.start.parties]
order_domain = [
('company', '=', self.start.company.id),
('customer', 'in', parties),
('order_date', '>=', self.start.start_date),
('order_date', '<=', self.start.end_date),
('state', '=', 'processed'),
('status_invoice', '!=', 'invoiced'),
('invoice', '=', None),
]
order_domain.extend(add_domain) if add_domain else None
orders = Order.search(
order_domain,
order=[('customer', 'ASC'), ('order_date', 'ASC')]
)
for party in set(parties):
orders_by_party = list(filter(lambda x: x.customer.id == party, orders))
if not orders_by_party:
continue
invoice = self.get_invoice_grouped(orders_by_party, party, journal.id, Invoice)
Order.write(orders_by_party, {'invoice': invoice.id, 'status_invoice': 'invoiced'})
return 'end'
def get_invoice_grouped(self, orders, party, journal_id, Invoice):
customer = orders[0].customer
address = customer.address_get(type='invoice')
data = {
'company': self.start.company.id,
'payment_term': customer.customer_payment_term,
'invoice_type': customer.invoice_type,
'currency': self.start.company.currency.id,
'party': customer.id,
'invoice_date': str(self.start.date_invoice),
'state': 'draft',
'authorization': orders[0].get_invoice_authorization(),
'operation_center': orders[0].operation_center.id,
'invoice_address': address.id,
'type': 'out',
'journal': journal_id,
'account': customer.account_receivable_used.id,
}
configuration = Pool().get('laboratory.configuration')(1)
Order = Pool().get('laboratory.order')
lines = []
for order in orders:
for line in order.lines:
_line = order.get_line_order(line=line)
product_exists = False
if configuration.group_invoice_lines:
for line_invoice in lines:
if line_invoice['product'] == _line['product']:
line_invoice['quantity'] += _line['quantity']
product_exists = True
break
if not product_exists:
lines.append(_line)
else:
lines.append(_line)
data['lines'] = [('create', lines)]
data['annexes'] = [('add', [order.id for order in orders])]
invoice, = Invoice.create([data])
invoice.on_change_annexes()
invoice.save()
return invoice
class PrintServiceOrder(Wizard):
'Print Service Order Report'
__name__ = 'laboratory.order.print'
start = StateTransition()
print_ = StateReport('laboratory.order')
def transition_start(self):
self.services_id = Transaction().context['active_id']
return 'print_'
def do_print_(self, action):
data = {}
data['id'] = self.services_ids
data['ids'] = [data['id']]
Order = Pool().get('laboratory.order')
order = Order(data['id'])
try:
action['email'] = eval(action['email'])
except:
action['email'] = {}
if order and order.party.email:
action['email'].update({"to": order.party.email})
return action, data
def transition_print_(self):
if self.services_ids:
return 'print_'
return 'end'
class OrderLine(DeactivableMixin, Workflow, ModelSQL, ModelView):
'Service Order Line'
__name__ = 'laboratory.order.line'
_rec_name = 'code'
code = fields.Char('Code', required=True, states=LINE_STATES, depends=['order_state'])
order = fields.Many2One('laboratory.order', 'Service Order',
select=True, required=True,
states={
'readonly': (
(Eval('order_state') != 'draft')
& Bool(Eval('order'))),
},
depends=['order_state']
)
test = fields.Many2One('product.product', 'Test', required=True,
states={
'readonly': ~Eval('order_state').in_(['draft', None])
}, depends=['order_state'],
domain=[('salable', '=', True)])
description = fields.Char('Description', states=LINE_STATES, depends=['order_state'])
unit_price = fields.Numeric(
'Unit Price', required=True, states=LINE_STATES, depends=['order_state'])
quantity = fields.Integer('Qty', required=True, states=LINE_STATES, depends=['order_state'])
analysis_date = fields.Date('Analysis Date')
order_state = fields.Function(
fields.Selection('get_order_states', "Order State"),
'on_change_with_order_state')
amount = fields.Function(fields.Numeric('Amount'), 'get_amount')
authorization = fields.Char('Authorization')
@classmethod
def __setup__(cls):
super().__setup__()
cls.__access__.add('order')
@staticmethod
def default_quantity():
return 1
def get_amount(self, name=None):
if self.quantity and self.unit_price:
return Decimal(self.quantity) * self.unit_price
@classmethod
def get_order_states(cls):
pool = Pool()
Laboratory = pool.get('laboratory.order')
return Laboratory.fields_get(['state'])['state']['selection']
@fields.depends('order', '_parent_order.state')
def on_change_with_order_state(self, name=None):
if self.order:
return self.order.state
@fields.depends(
'code', 'test', 'unit_price',
methods=['compute_unit_price'])
def on_change_test(self):
# self.code = None
# if self.test:
# self.code = self.test.reference
# self.unit_price = self.compute_unit_price()
pool = Pool()
price_list_id = None
if self.order.price_list:
price_list_id = self.order.price_list.id
self.code = None
if self.test:
PriceList = pool.get('product.price_list')
price_list = PriceList(price_list_id)
p_list = [line.product for line in price_list.lines]
if self.test in p_list:
self.code = self.test.reference
self.unit_price = self.compute_unit_price()
else:
raise UserError('No Esta en la lista de precios')
else:
raise UserError('Ya fue agregado el examen')
else:
raise UserError('No hay una lista de precios')
@fields.depends(
'test', 'quantity',
'order', '_parent_order.customer',
'_parent_order.price_list',
'_parent_order.order_date', '_parent_order.company')
def compute_unit_price(self):
pool = Pool()
Product = pool.get('product.product')
if not self.test:
return 0
context = {}
if self.order:
if self.order.customer:
context['customer'] = self.order.customer.id
if self.order.company:
context['currency'] = self.order.company.currency.id
context['company'] = self.order.company.id
if self.order.price_list:
context['price_list'] = self.order.price_list.id
context['sale_date'] = self.order.order_date
context['uom'] = self.test.sale_uom.id
with Transaction().set_context(context):
unit_price = Product.get_sale_price([self.test],
self.quantity or 0)[self.test.id]
if unit_price:
unit_price = round_price(unit_price)
return unit_price
class ServiceOrderReport(Report):
__name__ = 'laboratory.order.report'
@classmethod
def get_context(cls, records, header, data):
Company = Pool().get('company.company')
context = super(ServiceOrderReport, cls).get_context(records, header,
data)
report_id = data['action_id']
order_receip_id = Id('laboratory', 'service_order_receip').pyson()
if report_id == order_receip_id:
type_doc = 'order_receip'
else:
type_doc = 'order'
context['type_doc'] = type_doc
context['company'] = Company(Transaction().context.get('company'))
return context
class OrderPayment(Workflow, ModelSQL, ModelView):
'Order Payment'
__name__ = 'laboratory.order.payment'
_rec_name = 'number'
number = fields.Char('Number', help='Voucher number')
order = fields.Many2One('laboratory.order', 'Order', required=True)
amount = fields.Numeric('Amount', digits=(16, 2), required=True)
payment_mode = fields.Many2One('account.voucher.paymode', 'Pay Mode',
required=True)
payment_date = fields.Date('Payment Date', required=True)
move = fields.Many2One('account.move', 'Move', states={'readonly': True})
reconciled = fields.Boolean('Reconciled', states={'readonly': True})
amount_account = fields.Function(
fields.Numeric('Amount Account', digits=(16, 2)), 'get_amount_account')
def get_amount_account(self, name=None):
res = []
if self.move:
for line in self.move.lines:
if self.payment_mode.account.id == line.account.id:
res.append(abs(line.debit - line.credit))
return sum(res)
class Move(metaclass=PoolMeta):
__name__ = 'account.move'
@classmethod
def _get_origin(cls):
models = super()._get_origin()
models.append('laboratory.order.payment')
return models
class DetailedBillingAnalysisStart(ModelView):
'detailed billing analysis Start'
__name__ = 'laboratory.detailed_billing_analysis.start'
start_date = fields.Date('Start Date')
end_date = fields.Date('End Date')
class DetailedBillingAnalysisWizard(Wizard):
'detailed billing analysis Wizard'
__name__ = 'laboratory.detailed_billing_analysis'
start = StateView('laboratory.detailed_billing_analysis.start',
'laboratory.detailed_billing_analysis_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Ok', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('laboratory.detailed_billing_analysis.report')
def do_print_(self, action):
data = {
'start_date': self.start.start_date,
'end_date': self.start.end_date,
}
return action, data
def transition_print_(self):
return 'end'
class DetailedBillingAnalysisReport(Report):
"DetailedBillingAnalysis Report"
__name__ = 'laboratory.detailed_billing_analysis.report'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
user = pool.get('res.user')(Transaction().user)
Invoice = pool.get('account.invoice')
invoice_dom = [
('invoice_date', '>=', data['start_date']),
('invoice_date', '<=', data['end_date']),
('state', 'not in', ['rejected', 'draft']),
]
invoices = Invoice.search(invoice_dom)
report_context['invoices'] = invoices
report_context['start_date'] = data['start_date']
report_context['end_date'] = data['end_date']
report_context['company'] = user.company
return report_context
class AddPackageStart(ModelView):
'Add package Start'
__name__ = 'laboratory.add_package.start'
analysis_package = fields.Many2One('laboratory.analysis_package', 'Analysis Package')
class AddPackage(Wizard):
'Add Package'
__name__ = 'laboratory.add_package'
start = StateView(
'laboratory.add_package.start',
'laboratory.add_package_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Create Order Line', 'add_package', 'tryton-ok', default=True),
])
add_package = StateTransition()
def transition_add_package(self):
pool = Pool()
active_id = Transaction().context.get('active_id')
Order = pool.get('laboratory.order')
OrderLine = pool.get('laboratory.order.line')
order = Order(active_id)
customer = self.start.analysis_package.customer
if order.state == 'processed' or order.state == 'invoiced' or order.state == 'paid':
raise UserError('La orden ya fue procesada')
if customer:
if order.customer.id != customer.id:
raise UserError('El paquete seleccionado no pertenece al tercero ' + order.customer.name )
print(customer, order.customer.type_document)
if not customer and order.customer.type_document == '31':
raise UserError('El paquete seleccionado pertenece terceros con NIT')
order_lines = []
for line in self.start.analysis_package.lines:
order_line = OrderLine(
order=active_id,
code=line.test.reference,
test=line.test,
unit_price=line.unit_price,
quantity=1,
analysis_date=date.today(),
description='',
)
order_lines.append(order_line)
OrderLine.save(order_lines)
Order.save([order])
return 'end'