283 lines
10 KiB
Python
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'
|