trytonpsk-purchase_report/purchase.py

283 lines
10 KiB
Python

# 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 __future__ import with_statement
from datetime import date
from decimal import Decimal
from trytond.model import fields, ModelView
from trytond.report import Report
from trytond.pool import PoolMeta, Pool
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, Button, StateTransition, StateReport
from trytond.pyson import Eval
from trytond.model.exceptions import AccessError
from trytond.i18n import gettext
_STATES = {
'readonly': Eval('state') != 'draft',
}
class Purchase(metaclass=PoolMeta):
__name__ = 'purchase.purchase'
@classmethod
def __setup__(cls):
super(Purchase, cls).__setup__()
@classmethod
def confirm(cls, purchases):
for purchase in purchases:
duplicates = cls.search_read([
('reference', '=', purchase.reference),
('party', '=', purchase.party.id),
('purchase_date', '=', purchase.purchase_date),
], fields_names=['reference'])
if len(duplicates) >= 2:
raise AccessError(gettext('purchase_report.msg_duplicate_purchase', s=purchase.reference))
super(Purchase, cls).confirm(purchases)
@classmethod
def import_data(cls, fields_names, data):
pool = Pool()
Product = pool.get('product.product')
Party = pool.get('party.party')
Address = pool.get('party.address')
Location = pool.get('stock.location')
count = 0
purchase_to_create = {}
party_id = None
for row in data:
if row[0] != '':
partys = Party.search([
('id_number', '=', row[0])
])
if not partys:
continue
party_id = partys[0].id
address = Address.search([
('party', '=', party_id)
])
address_id = address[0].id if address else None
warehouses = Location.search([('code', '=', row[2])])
warehouse_id = None
if warehouses:
warehouse_id = warehouses[0].id
purchase = {
'purchase_date': row[1],
'party': party_id,
'warehouse': warehouse_id,
'reference': row[3],
'invoice_address': address_id,
'payment_term': None,
'lines': [('create', [])]
}
purchase_to_create[party_id] = purchase
count += 1
products = Product.search([
('code', '=', row[5])
])
if not products:
continue
product = products[0]
product_id = product.id
line = {
'product': product_id,
'quantity': row[4],
'description': row[8] if row[8] != '' else product.description,
'unit': 1,
'unit_price': Decimal(row[7]),
'taxes': [('add', product.supplier_taxes_used)],
}
purchase_to_create[party_id]['lines'][0][1].append(line)
cls.create(purchase_to_create.values())
return count
class PurchaseLine(metaclass=PoolMeta):
__name__ = 'purchase.line'
date_start = fields.Date('Date Start')
date_end = fields.Date('Date End')
party = fields.Function(fields.Many2One('party.party', 'Party'), 'get_parent_data')
date = fields.Function(fields.Date('Date'), 'get_parent_data')
@classmethod
def __setup__(cls):
super(PurchaseLine, cls).__setup__()
def get_parent_data(self, name=None):
if name == 'date':
return self.purchase.purchase_date
if name == 'party':
return self.purchase.party.id
class PurchaseDetailedReport(Report):
__name__ = 'purchase_report.detailed'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
user = Pool().get('res.user')(Transaction().user)
report_context['company'] = user.company
return report_context
class PurchaseAnalyticStart(ModelView):
'Purchase Analytic Report Start'
__name__ = 'purchase_report.analytic.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)
@staticmethod
def default_company():
return Transaction().context.get('company')
@staticmethod
def default_end_date():
Date = Pool().get('ir.date')
return Date.today()
class PurchaseAnalytic(Wizard):
'Purchase Analytic Report'
__name__ = 'purchase_report.analytic'
start = StateView('purchase_report.analytic.start',
'purchase_report.purchase_analytic_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('purchase_report.analytic.report')
def do_print_(self, action):
data = {
'company': self.start.company.id,
'start_date': self.start.start_date,
'end_date': self.start.end_date,
}
return action, data
def transition_print_(self):
return 'end'
class PurchaseAnalyticReport(Report):
__name__ = 'purchase_report.analytic.report'
@classmethod
def compute_amount_tax(cls, line):
Tax = Pool().get('account.tax')
tax_list = Tax.compute(Tax.browse(line['taxes']),
line['unit_price'] or Decimal('0.0'),
line['quantity'] or 0.0)
return sum([t['amount'] for t in tax_list], Decimal('0.0'))
@classmethod
def _get_rec(cls, line):
analytic_account = None
if line['analytic_accounts.']:
analytic_account = line['analytic_accounts.'][0]['account.']
inv_unit_price = Decimal(0)
if line['invoice_lines.']:
inv_unit_price = line['invoice_lines.'][0]['unit_price']
value = {
'reference': line['purchase.']['reference'],
'purchase_date': line['purchase.']['purchase_date'],
'state': line['purchase.']['state'],
'shipment_state': line['purchase.']['shipment_state'],
'invoice_state': line['purchase.']['invoice_state'],
'id_number': line['purchase.']['party.']['id_number'],
'name': line['purchase.']['party.']['name'],
'warehouse': line['purchase.']['warehouse.']['name'],
'description': line['description'],
'unit_name': line['unit.']['name'],
'quantity': line['quantity'],
'unit_price': line['unit_price'],
'analytic_account': analytic_account['code'] + ' ' + analytic_account['name'] if analytic_account else '',
'taxes': list(line['taxes']),
'qty_received': sum([r['quantity'] for r in line['moves.']]),
'amount': line['amount'],
'inv_unit_price': inv_unit_price
}
tax_amount = cls.compute_amount_tax(value)
full_amount = value['amount'] + tax_amount
value.update({
'tax_amount': tax_amount,
'full_amount': full_amount,
})
return value
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Company = pool.get('company.company')
PurchaseLine = pool.get('purchase.line')
fields_names = ['purchase.reference', 'purchase.purchase_date', 'purchase.party.id_number',
'purchase.party.name', 'description', 'unit.name', 'quantity', 'unit_price',
'purchase.state', 'purchase.shipment_state', 'purchase.invoice_state',
'analytic_accounts.account.name', 'analytic_accounts.account.code', 'taxes',
'invoice_lines.unit_price', 'moves.quantity', 'amount', 'purchase.warehouse.name'
]
lines = PurchaseLine.search_read([
('purchase.company', '=', data['company']),
('purchase.purchase_date', '>=', data['start_date']),
('purchase.purchase_date', '<=', data['end_date']),
], fields_names=fields_names, order=[('purchase.purchase_date', 'ASC')])
records = []
records_append = records.append
get_rec = cls._get_rec
for line in lines:
records_append(get_rec(line))
report_context['records'] = records
report_context['company'] = Company(data['company'])
return report_context
class PurchaseForceCancel(Wizard):
'Purchase Force Cancel'
__name__ = 'purchase.purchase.force_cancel'
start_state = 'force_cancel'
force_cancel = StateTransition()
def transition_force_cancel(self):
pool = Pool()
Purchase = pool.get('purchase.purchase')
Invoice = pool.get('account.invoice')
Move = pool.get('stock.move')
ShipmentIn = pool.get('stock.shipment.in')
cursor = Transaction().connection.cursor()
ids = Transaction().context['active_ids']
moves = []
if ids:
purchases = Purchase.browse(ids)
for purchase in purchases:
number_invoices = []
if purchase.invoices:
Invoice.cancel(purchase.invoices)
if purchase.shipments:
for s in purchase.shipments:
cursor.execute("UPDATE stock_shipment_in SET state='draft' WHERE id in (%s)" % (s.id))
for m in s.incoming_moves:
moves.append(str(m.id))
for m in s.inventory_moves:
moves.append(str(m.id))
if moves:
moves_ids = ", ".join(moves)
cursor.execute("UPDATE stock_move SET state='draft' WHERE id in (%s)" % (moves_ids))
Move.cancel(s.incoming_moves)
Move.cancel(s.inventory_moves)
ShipmentIn.cancel(purchase.shipments)
Purchase.write([purchase], {'state': 'cancel'})
return 'end'