762 lines
26 KiB
Python
762 lines
26 KiB
Python
# This file is part of the sale_weight module for Tryton.
|
|
# The COPYRIGHT file at the top level of this repository contains the full
|
|
# copyright notices and license terms.
|
|
from decimal import Decimal
|
|
from datetime import timedelta, date
|
|
from dateutil.relativedelta import *
|
|
|
|
from trytond.model import Workflow, ModelView, ModelSQL, fields
|
|
from trytond.pool import Pool
|
|
from trytond.pyson import Eval
|
|
from trytond.transaction import Transaction
|
|
from trytond.wizard import Wizard, StateView, Button, StateReport, StateTransition
|
|
from trytond.report import Report
|
|
|
|
conversor = None
|
|
try:
|
|
from numword import numword_es
|
|
conversor = numword_es.NumWordES()
|
|
except:
|
|
print("Warning: Does not possible import numword module!")
|
|
print("Please install it...!")
|
|
|
|
|
|
__all__ = ['SaleContract', 'SaleContractLine', 'SaleContractReport',
|
|
'ContractProductLine', 'SaleContractByMonthStart', 'TypeContract',
|
|
'SaleContractByMonth', 'SaleContractByMonthReport',
|
|
'CreateInvoicesFromContract', 'CreateInvoicesFromContractStart'
|
|
]
|
|
|
|
STATES = {
|
|
'readonly': Eval('state') != 'draft',
|
|
}
|
|
|
|
STATES_LINE = {
|
|
'readonly': Eval('state') != 'pending',
|
|
}
|
|
|
|
_ZERO = Decimal('0.0')
|
|
|
|
RANGE_MONTH = [(str(d + 1), str(d + 1)) for d in range(28)] + [('', '')]
|
|
|
|
TYPE_INVOICE = [
|
|
('', ''),
|
|
('C', 'Computador'),
|
|
('P', 'POS'),
|
|
('M', 'Manual'),
|
|
('1', 'Venta Electronica'),
|
|
('2', 'Exportacion'),
|
|
('3', 'Factura por Contingencia Facturador'),
|
|
('4', 'Factura por Contingencia DIAN'),
|
|
('91', 'Nota Crédito Eléctronica'),
|
|
('92', 'Nota Débito Eléctronica'),
|
|
]
|
|
|
|
|
|
class TypeContract(ModelSQL, ModelView):
|
|
"Type Sale Contract"
|
|
__name__ = 'sale.contract.type'
|
|
name = fields.Char('Name')
|
|
active = fields.Boolean('Active')
|
|
kind = fields.Selection([
|
|
('open', 'Open'),
|
|
('close', 'Close'),
|
|
], 'Kind', select=True)
|
|
invoice_frecuency = fields.Selection([
|
|
('biweekly', 'Biweekly'),
|
|
('monthly', 'Monthly'),
|
|
('annual', 'Annual'),
|
|
('just_one', 'Just One'),
|
|
], 'Invoice Frecuency', select=True, required=True)
|
|
description_template = fields.Char('Description Template')
|
|
|
|
|
|
class SaleContract(Workflow, ModelSQL, ModelView):
|
|
"Sale Contract"
|
|
__name__ = 'sale.contract'
|
|
_rec_name = 'number'
|
|
number = fields.Char('Number', readonly=True)
|
|
party = fields.Many2One('party.party', 'Party', required=True,
|
|
select=True, states= STATES)
|
|
contract_date = fields.Date('Contract Date', required=True, states=STATES)
|
|
date = fields.Date('Date')
|
|
payment_term = fields.Many2One('account.invoice.payment_term',
|
|
'Payment Term', required=True, states=STATES)
|
|
lines = fields.One2Many('sale.contract.line', 'contract', 'Lines',
|
|
states={
|
|
'readonly': Eval('state') == 'finished',
|
|
# 'required': Eval('state') == 'finished',
|
|
}, depends=['state'])
|
|
company = fields.Many2One('company.company', 'Company', required=True,
|
|
states=STATES)
|
|
type = fields.Many2One('sale.contract.type', 'Type', states=STATES,
|
|
required=True)
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('confirmed', 'Confirmed'),
|
|
('finished', 'Finished'),
|
|
('canceled', 'Canceled'),
|
|
], 'State', readonly=True, select=True)
|
|
state_string = state.translated('state')
|
|
total_amount = fields.Numeric('Total Amount', digits=(16, 2),
|
|
required=True, states={
|
|
'readonly': True,
|
|
}, depends=['invoices_number'])
|
|
validity_contract = fields.Char('Validity Contract', states=STATES)
|
|
monthly_cutoff_date = fields.Selection(RANGE_MONTH, 'Monthly Cut Off Date',
|
|
states=STATES)
|
|
start_date = fields.Date('Start Date', states=STATES, required=True)
|
|
end_date = fields.Date('End Date', states={
|
|
'readonly': Eval('state') != 'draft',
|
|
})
|
|
description = fields.Char('Description', states=STATES, required=True)
|
|
invoices_number = fields.Integer('Invoices Number', states={
|
|
'readonly': Eval('state') != 'draft',
|
|
})
|
|
product_lines = fields.One2Many('sale.contract.product_line', 'contract',
|
|
'Product Lines', required=True, states=STATES)
|
|
fee_amount = fields.Function(fields.Numeric('Fee Amount'),
|
|
'get_fee_amount')
|
|
total_amount_words = fields.Function(fields.Char('Total Amount Words'),
|
|
'get_total_amount_words')
|
|
comment = fields.Text('Comment', states=STATES)
|
|
salesman = fields.Many2One('company.employee', 'Salesman',
|
|
select=True, states=STATES,)
|
|
sales = fields.Function(fields.Many2Many('sale.sale', None, None,
|
|
'Sales'), 'get_sales')
|
|
invoice_method = fields.Selection([
|
|
('manual', 'Manual'),
|
|
('order', 'On Order Processed'),
|
|
('shipment', 'On Shipment Sent'),
|
|
], 'Invoice Method', required=True, select=True)
|
|
reference = fields.Char('Reference')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(SaleContract, cls).__setup__()
|
|
cls._order.insert(0, ('date', 'DESC'))
|
|
cls._error_messages.update({
|
|
'payment_term_missing': 'The payterm is missing!',
|
|
'sequence_missing': 'The sequence is missing!',
|
|
'lines_processed': ('Sale Contract "%s" can not deleted '
|
|
'because has lines processed'),
|
|
'delete_cancel': ('Sale Contract "%s" must be canceled before '
|
|
'deletion.'),
|
|
'sales_pending': ('You can not to finish contract because '
|
|
'has sales pending!'),
|
|
})
|
|
cls._transitions |= set((
|
|
('draft', 'confirmed'),
|
|
('draft', 'canceled'),
|
|
('confirmed', 'draft'),
|
|
('canceled', 'draft'),
|
|
('confirmed', 'finished'),
|
|
('finished', 'confirmed'),
|
|
))
|
|
cls._buttons.update({
|
|
'create_lines': {
|
|
'invisible': Eval('state') != 'confirmed',
|
|
},
|
|
'cancel': {
|
|
'invisible': Eval('state') != 'draft',
|
|
},
|
|
'draft': {
|
|
'invisible': ~Eval('state').in_(['canceled', 'confirmed']),
|
|
},
|
|
'confirm': {
|
|
'invisible': Eval('state').in_(['canceled', 'confirmed']),
|
|
},
|
|
'finish': {
|
|
'invisible': Eval('state') != 'confirmed',
|
|
},
|
|
})
|
|
|
|
@staticmethod
|
|
def default_state():
|
|
return 'draft'
|
|
|
|
@staticmethod
|
|
def default_invoice_method():
|
|
return ''
|
|
|
|
@staticmethod
|
|
def default_contract_date():
|
|
Date = Pool().get('ir.date')
|
|
return Date.today()
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company') or False
|
|
|
|
@classmethod
|
|
def delete(cls, contracts):
|
|
# Cancel before delete
|
|
cls.cancel(contracts)
|
|
for contract in contracts:
|
|
lines = [l for l in contract.lines if l.state in ('processed', 'paid')]
|
|
if lines:
|
|
cls.raise_user_error('lines_processed', (contract.rec_name,))
|
|
if contract.state != 'canceled':
|
|
cls.raise_user_error('delete_cancel', (contract.rec_name,))
|
|
super(SaleContract, cls).delete(contracts)
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('draft')
|
|
def draft(cls, contracts):
|
|
pass
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('finished')
|
|
def finish(cls, contracts):
|
|
for contract in contracts:
|
|
contract.check_sales()
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('canceled')
|
|
def cancel(cls, contracts):
|
|
pass
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('confirmed')
|
|
def confirm(cls, contracts):
|
|
for contract in contracts:
|
|
contract.set_number()
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
def create_lines(cls, contracts):
|
|
for contract in contracts:
|
|
if contract.type.kind == 'close':
|
|
contract.forecast_sales()
|
|
|
|
def check_sales(self):
|
|
for line in self.lines:
|
|
if line.state == 'pending':
|
|
self.raise_user_error('sales_pending')
|
|
|
|
def forecast_sales(self):
|
|
Line = Pool().get('sale.contract.line')
|
|
lines_to_create = []
|
|
for i in range(self.invoices_number):
|
|
date_ = self.start_date + timedelta(30.5 * i)
|
|
lines_to_create.append({
|
|
'contract': self.id,
|
|
'date': date_,
|
|
'sale_amount': self.fee_amount,
|
|
'description': self.description,
|
|
'state': 'pending',
|
|
})
|
|
Line.create(lines_to_create)
|
|
|
|
def set_number(self):
|
|
'''
|
|
Set sequence number
|
|
'''
|
|
pool = Pool()
|
|
config = pool.get('sale.configuration')(1)
|
|
Sequence = pool.get('ir.sequence')
|
|
if self.number:
|
|
return
|
|
if not config.sale_contract_sequence:
|
|
self.raise_user_error('sequence_missing')
|
|
seq = config.sale_contract_sequence.id
|
|
self.write([self], {'number': Sequence.get_id(seq)})
|
|
|
|
def get_fee_amount(self, name=None):
|
|
return sum([l.unit_price for l in self.product_lines if l.type == 'line' and l.unit_price])
|
|
|
|
def get_total_amount_words(self, name=None):
|
|
if self.total_amount and conversor:
|
|
num = (conversor.cardinal(int(self.total_amount))).upper()
|
|
return num
|
|
|
|
def get_sales(self, name):
|
|
sales_ids = []
|
|
for line in self.lines:
|
|
if line.sale:
|
|
sales_ids.append(line.sale.id)
|
|
return sales_ids
|
|
|
|
@fields.depends('product_lines', 'invoices_number')
|
|
def on_change_with_total_amount(self):
|
|
res = _ZERO
|
|
val_amount = _ZERO
|
|
if self.invoices_number and self.product_lines:
|
|
for line in self.product_lines:
|
|
if not line.unit_price:
|
|
continue
|
|
val_amount += line.unit_price
|
|
res = val_amount * self.invoices_number
|
|
return res
|
|
|
|
def validate_contract(self):
|
|
pass
|
|
|
|
|
|
class SaleContractLine(Workflow, ModelSQL, ModelView):
|
|
"Sale Contract Line"
|
|
__name__ = 'sale.contract.line'
|
|
_rec_name = 'description'
|
|
contract = fields.Many2One('sale.contract', 'Contract', select=True,
|
|
ondelete='CASCADE', states=STATES_LINE)
|
|
date = fields.Date('Date', required=True, states=STATES_LINE)
|
|
sale_amount = fields.Numeric('Sale Amount', digits=(16, 2),
|
|
required=True, states=STATES_LINE)
|
|
state = fields.Selection([
|
|
('pending', 'Pending'),
|
|
('processed', 'Processed'),
|
|
('paid', 'Paid'),
|
|
('canceled', 'Canceled'),
|
|
], 'State', readonly=True, select=True)
|
|
sale = fields.Many2One('sale.sale', 'Sale', states={
|
|
'readonly': True,
|
|
})
|
|
description = fields.Text('Description', states=STATES_LINE)
|
|
only_first_invoice = fields.Boolean('Only First Invoice', states=STATES_LINE)
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(SaleContractLine, cls).__setup__()
|
|
cls._transitions |= set((
|
|
('pending', 'processed'),
|
|
('processed', 'canceled'),
|
|
('processed', 'paid'),
|
|
))
|
|
cls._buttons.update({
|
|
'cancel': {
|
|
'invisible': Eval('state') != 'paid'
|
|
},
|
|
'process': {
|
|
'invisible': Eval('state') != 'pending',
|
|
},
|
|
})
|
|
|
|
@staticmethod
|
|
def default_state():
|
|
return 'pending'
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('processed')
|
|
def process(cls, lines):
|
|
for line in lines:
|
|
line._create_sale(line.contract)
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('canceled')
|
|
def cancel(cls, lines):
|
|
pass
|
|
|
|
def _create_sale(self, contract):
|
|
pool = Pool()
|
|
Party = pool.get('party.party')
|
|
Sale = pool.get('sale.sale')
|
|
shop_id = Transaction().context.get('shop')
|
|
description = contract.description
|
|
if contract.type.description_template and contract.monthly_cutoff_date:
|
|
try:
|
|
start_date = date(self.date.year, self.date.month, int(contract.monthly_cutoff_date))
|
|
end_date = start_date + relativedelta(months=+1)
|
|
description = contract.type.description_template % (start_date, end_date)
|
|
except:
|
|
pass
|
|
|
|
sale_to_create = {
|
|
'company': contract.company.id,
|
|
'party': contract.party.id,
|
|
'sale_date': self.date,
|
|
'state': 'draft',
|
|
'salesman': contract.salesman.id if contract.salesman else None,
|
|
'invoice_address': Party.address_get(contract.party, type='invoice'),
|
|
'shipment_address': Party.address_get(contract.party, type='delivery'),
|
|
'description': description,
|
|
'shop': shop_id if shop_id else None,
|
|
'invoice_method': 'order',
|
|
'shipment_method': 'order',
|
|
}
|
|
if contract.payment_term:
|
|
sale_to_create['payment_term'] = contract.payment_term.id
|
|
lines_to_create = []
|
|
for line in contract.product_lines:
|
|
value = self.get_sale_line(contract, line)
|
|
lines_to_create.append(value)
|
|
sale_to_create['lines'] = [('create', lines_to_create)]
|
|
sale, = Sale.create([sale_to_create])
|
|
self.write([self], {'sale': sale.id})
|
|
sale.write([sale], {'contract_line': self.id})
|
|
return sale
|
|
|
|
|
|
def get_sale_line(self, contract, line):
|
|
if line.type == 'subtotal':
|
|
value = {
|
|
'type': line.type,
|
|
'description': line.description,
|
|
}
|
|
else:
|
|
value = {
|
|
'type': line.type,
|
|
'product': line.product.id,
|
|
'quantity': 1,
|
|
'unit': line.product.default_uom.id,
|
|
'unit_price': line.unit_price,
|
|
'taxes': [],
|
|
'description': line.description,
|
|
}
|
|
taxes_ids = self.get_taxes(contract.party, line.product)
|
|
value['taxes'] = [('add', taxes_ids)]
|
|
return value
|
|
|
|
def get_taxes(self, party, product):
|
|
taxes = []
|
|
pattern = {}
|
|
for tax in product.customer_taxes_used:
|
|
if party.customer_tax_rule:
|
|
tax_ids = party.customer_tax_rule.apply(tax, pattern)
|
|
if tax_ids:
|
|
taxes.extend(tax_ids)
|
|
continue
|
|
taxes.append(tax.id)
|
|
if party.customer_tax_rule:
|
|
for line in party.customer_tax_rule.lines:
|
|
tax_ids = party.customer_tax_rule.apply(line.tax, pattern)
|
|
if tax_ids:
|
|
taxes.extend(tax_ids)
|
|
|
|
return taxes
|
|
|
|
def validate_contract_line(self):
|
|
pass
|
|
|
|
def _process_sale(self, invoice_type=None, period=None):
|
|
Sale = Pool().get('sale.sale')
|
|
if not self.sale:
|
|
return
|
|
if invoice_type:
|
|
Sale.write([self.sale], {'invoice_type': invoice_type})
|
|
if period:
|
|
Sale.write([self.sale], {'reference': period.name})
|
|
|
|
Sale.quote([self.sale])
|
|
if self.contract.invoice_method:
|
|
self.sale.invoice_method = self.contract.invoice_method
|
|
Sale.confirm([self.sale])
|
|
Sale.process([self.sale])
|
|
for invoice in self.sale.invoices:
|
|
invoice.invoice_date = self.date
|
|
invoice.reference = self.sale.reference or ''
|
|
invoice.save()
|
|
|
|
|
|
class ContractProductLine(ModelSQL, ModelView):
|
|
"Contract Product Line"
|
|
__name__ = 'sale.contract.product_line'
|
|
contract = fields.Many2One('sale.contract', 'Contract', select=True,
|
|
ondelete='CASCADE')
|
|
product = fields.Many2One('product.product', 'Product',
|
|
states={
|
|
'invisible': Eval('type') != 'line',
|
|
'required': Eval('type') == 'line',
|
|
},
|
|
depends=['type']
|
|
)
|
|
unit_price = fields.Numeric('Unit Price', digits=(16, 2),
|
|
states={
|
|
'invisible': Eval('type') != 'line',
|
|
'required': Eval('type') == 'line',
|
|
},
|
|
depends=['type']
|
|
)
|
|
description = fields.Text('Description',required=True)
|
|
only_first_invoice = fields.Boolean('Only First Invoice')
|
|
type = fields.Selection([
|
|
('line', 'Line'),
|
|
('subtotal', 'Subtotal'),
|
|
], 'Type', select=True, required=True
|
|
)
|
|
|
|
@fields.depends('product')
|
|
def on_change_with_unit_price(self):
|
|
if self.product:
|
|
return self.product.list_price
|
|
|
|
|
|
class SaleContractReport(Report):
|
|
__name__ = 'sale_contract.contract_report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, data):
|
|
report_context = super(SaleContractReport, cls).get_context(records, data)
|
|
Company = Pool().get('company.company')
|
|
company_id = Transaction().context.get('company')
|
|
report_context['company'] = Company(company_id)
|
|
return report_context
|
|
|
|
|
|
class SaleContractByMonthStart(ModelView):
|
|
'Sale Contract By Month Start'
|
|
__name__ = 'sale.contract_by_month.start'
|
|
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year', required=True)
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
period = fields.Many2One('account.period', 'Period',
|
|
depends=['fiscalyear'], required=True, domain=[
|
|
('fiscalyear', '=', Eval('fiscalyear')),
|
|
])
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@fields.depends('fiscalyear')
|
|
def on_change_fiscalyear(self):
|
|
self.period = None
|
|
|
|
@staticmethod
|
|
def default_fiscalyear():
|
|
FiscalYear = Pool().get('account.fiscalyear')
|
|
return FiscalYear.find(
|
|
Transaction().context.get('company'), exception=False)
|
|
|
|
|
|
class SaleContractByMonth(Wizard):
|
|
'Sale Contract By Month'
|
|
__name__ = 'sale.contract_by_month'
|
|
start = StateView('sale.contract_by_month.start',
|
|
'sale_contract.sale_contract_by_month_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Print', 'print_', 'tryton-ok', default=True),
|
|
])
|
|
print_ = StateReport('sale_contract.contract_by_month_report')
|
|
|
|
def do_print_(self, action):
|
|
data = {
|
|
'company': self.start.company.id,
|
|
'fiscalyear': self.start.fiscalyear.id,
|
|
'period': self.start.period.id,
|
|
}
|
|
return action, data
|
|
|
|
def transition_print_(self):
|
|
return 'end'
|
|
|
|
|
|
class SaleContractByMonthReport(Report):
|
|
'Contract By Month Report'
|
|
__name__ = 'sale_contract.contract_by_month_report'
|
|
|
|
@classmethod
|
|
def get_context(cls, records, data):
|
|
report_context = super(SaleContractByMonthReport, cls).get_context(records, data)
|
|
pool = Pool()
|
|
SaleContract = pool.get('sale.contract')
|
|
Period = pool.get('account.period')
|
|
period = Period(data['period'])
|
|
|
|
records = SaleContract.search([
|
|
('company', '=', data['company']),
|
|
('contract_date', '>=', period.start_date),
|
|
('contract_date', '<=', period.end_date),
|
|
('state', 'in', ['confirmed', 'finished']),
|
|
])
|
|
|
|
total_amount = []
|
|
for contract in records:
|
|
total_amount.append(contract.total_amount)
|
|
|
|
report_context['sum_total_amount'] = sum(total_amount)
|
|
report_context['period'] = period.name
|
|
report_context['today'] = date.today()
|
|
report_context['records'] = records
|
|
|
|
return report_context
|
|
|
|
|
|
class CreateInvoicesFromContractStart(ModelView):
|
|
'Create Invoices From Contract Start'
|
|
__name__ = 'sale.create_invoices_from_contract.start'
|
|
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year', required=True)
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
period = fields.Many2One('account.period', 'Period',
|
|
depends=['fiscalyear'], required=True, domain=[
|
|
('fiscalyear', '=', Eval('fiscalyear')),
|
|
])
|
|
invoice_type = fields.Selection(TYPE_INVOICE, 'Type Invoice')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@fields.depends('fiscalyear')
|
|
def on_change_fiscalyear(self):
|
|
self.period = None
|
|
|
|
@staticmethod
|
|
def default_fiscalyear():
|
|
FiscalYear = Pool().get('account.fiscalyear')
|
|
return FiscalYear.find(
|
|
Transaction().context.get('company'), exception=False)
|
|
|
|
|
|
class CreateInvoicesFromContract(Wizard):
|
|
'Create Invoices From Contract'
|
|
__name__ = 'sale.create_invoices_from_contract'
|
|
start = StateView('sale.create_invoices_from_contract.start',
|
|
'sale_contract.create_invoices_from_contract_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Create', 'accept', 'tryton-ok', default=True),
|
|
])
|
|
accept = StateTransition()
|
|
|
|
def transition_accept(self):
|
|
pool = Pool()
|
|
Contract = pool.get('sale.contract')
|
|
Line = Pool().get('sale.contract.line')
|
|
lines = Line.search([
|
|
('contract.state', '=', 'confirmed'),
|
|
('date', '>=', self.start.period.start_date),
|
|
('date', '<=', self.start.period.end_date),
|
|
])
|
|
lines_invoiced = []
|
|
if lines:
|
|
lines_invoiced = [line.contract.id for line in lines]
|
|
|
|
dom_contract = [
|
|
['AND',
|
|
['OR', [
|
|
('type.kind', '=', 'open'),
|
|
('state', '=', 'confirmed'),
|
|
('end_date', '>=', self.start.period.start_date),
|
|
],[
|
|
('type.kind', '=', 'open'),
|
|
('state', '=', 'confirmed'),
|
|
('end_date', '=', None),
|
|
],
|
|
],],
|
|
]
|
|
|
|
if lines_invoiced:
|
|
dom_contract = [
|
|
['AND',
|
|
['OR', [
|
|
('type.kind', '=', 'open'),
|
|
('state', '=', 'confirmed'),
|
|
('end_date', '>=', self.start.period.start_date),
|
|
('id', 'not in', lines_invoiced),
|
|
],[
|
|
('type.kind', '=', 'open'),
|
|
('state', '=', 'confirmed'),
|
|
('end_date', '=', None),
|
|
('id', 'not in', lines_invoiced),
|
|
],
|
|
],],
|
|
]
|
|
|
|
contracts = Contract.search(dom_contract)
|
|
|
|
lines_to_create = []
|
|
date_ = self.start.period.start_date
|
|
for contract in contracts:
|
|
contract.validate_contract()
|
|
day_ = date_.day
|
|
if contract.start_date > date_:
|
|
day_ = contract.start_date.day
|
|
lines_to_create.append({
|
|
'contract': contract.id,
|
|
'date': date(date_.year, date_.month, day_),
|
|
'sale_amount': contract.fee_amount,
|
|
'description': contract.description,
|
|
'state': 'pending',
|
|
})
|
|
# date_ = self.start.period.start_date
|
|
lines = Line.create(lines_to_create)
|
|
for contract_line in lines:
|
|
Line.process([contract_line])
|
|
if not contract_line.sale:
|
|
continue
|
|
contract_line.validate_contract_line()
|
|
contract_line._process_sale(self.start.invoice_type, self.start.period)
|
|
return 'end'
|
|
|
|
|
|
class SaleContractFromPartyStart(ModelView):
|
|
'Create Sale Contract From Parties Start'
|
|
__name__ = 'sale.create_contract_from_party.start'
|
|
start_date = fields.Date('Start Date', required=True)
|
|
end_date = fields.Date('End Date',)
|
|
payment_term = fields.Many2One('account.invoice.payment_term',
|
|
'Payment Term', required=True)
|
|
parties = fields.One2Many('party.party', None,
|
|
'Parties', add_remove=[], required=True)
|
|
products = fields.One2Many('product.product', None,
|
|
'Products', add_remove=[], required=True)
|
|
# salesman = fields.Many2One('company.employee', 'Salesman')
|
|
company = fields.Many2One('company.company', 'Company', required=True)
|
|
type_contract = fields.Many2One('sale.contract.type', 'Type Contract', required=True)
|
|
cuttof_day = fields.Numeric('cuttof_day')
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company')
|
|
|
|
@fields.depends('start_date', 'end_date')
|
|
def on_change_start_date(self):
|
|
if self.start_date:
|
|
self.end_date = self.start_date + timedelta(days=365)
|
|
|
|
|
|
class SaleContractFromParty(Wizard):
|
|
'Create Contract From Parties'
|
|
__name__ = 'sale.create_contract_from_party'
|
|
start = StateView('sale.create_contract_from_party.start',
|
|
'sale_contract.create_contract_from_party_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Create', 'accept', 'tryton-ok', default=True),
|
|
])
|
|
accept = StateTransition()
|
|
|
|
def transition_accept(self):
|
|
pool = Pool()
|
|
Contract = pool.get('sale.contract')
|
|
Date = pool.get('ir.date')
|
|
|
|
for party in self.start.parties:
|
|
contract_to_create = {
|
|
'company': self.start.company.id,
|
|
'party': party.id,
|
|
'contract_date': self.start.start_date or Date.today(),
|
|
'payment_term': self.start.payment_term.id or None,
|
|
'type': self.start.type_contract.id,
|
|
'start_date': self.start.start_date,
|
|
'end_date': self.start.end_date or None,
|
|
'comment': '',
|
|
# 'salesman': self.start.salesman.id if self.start.salesman else None,
|
|
'total_amount': 1,
|
|
'description': ' ',
|
|
'invoices_number': 1,
|
|
'invoice_method': 'order',
|
|
'state': 'draft',
|
|
'product_lines': [],
|
|
'monthly_cutoff_date': self.start.cuttof_day or None,
|
|
}
|
|
|
|
lines_to_create = []
|
|
for product in self.start.products:
|
|
value = {
|
|
# 'analytic_account': None,
|
|
'description': product.description or product.name,
|
|
'product': product.id,
|
|
'type': 'line',
|
|
'unit_price': product.list_price,
|
|
'only_first_invoice': False,
|
|
}
|
|
lines_to_create.append(value)
|
|
contract_to_create['product_lines'] = [('create', lines_to_create)]
|
|
contract = Contract.create([contract_to_create])
|
|
|
|
return 'end'
|