Browse Source

[ADD] Calculo de Cuota

adrielso 5 years ago
parent
commit
f8dfa6153e

+ 2 - 0
__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import models

+ 8 - 0
__openerp__.py

@@ -19,10 +19,18 @@ Opciones.
         'base',
         'sale',
         'account',
+        'eiru_assets',
         'currency_utility',
     ],
     'data' : [
+        'security/ir.model.access.csv',
+        'views/template.xml',
+        'views/eiru_sale_utility_tool.xml',
+        'views/account_payment_term_type.xml',
+        'views/account_sale_term.xml',
     ],
     'qweb' : [
+        'static/src/xml/*.xml',
+        'static/src/xml/modal/*.xml'
     ]
 }

+ 8 - 0
models/__init__.py

@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+import eiru_utility_tool_sale
+import payment_term_configurator
+import account_payment_term_type
+import accont_payments_term_config
+import account_sale_term
+import purchase_order_term_configurator

+ 34 - 0
models/accont_payments_term_config.py

@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+from openerp import models, fields, tools, api
+import openerp.addons.decimal_precision as dp
+
+class AccontPaymentsTermConfig(models.Model):
+    _name = 'accont.payments.term.config'
+
+    name = fields.Char('Name', required=True, readonly=True)
+    interest_rate = fields.Float('Tasa de interés', digits=(3,6), digits_compute=dp.get_precision('Interest'), required=True, help="Tasa de interés %")
+    message_default = fields.Char('Message', default='La tasa de interés por defecto es 4% mensual, tasa diaria (4 / 30 = 0,1333).')
+    compute =  fields.Boolean(help="Indica si sera calculado los interés")
+    comment = fields.Text('Comment', help="Información adicional")
+
+    @api.model
+    def _create_default_config(self):
+        config = {
+            'name': 'Interés por cambio de fecha de cuota',
+            'interest_rate': '0.1333',
+            'compute': True,
+        }
+
+        termConfig = self.env['accont.payments.term.config'].search([('name','=', config['name'])])
+        if (not termConfig):
+            self.env['accont.payments.term.config'].create({
+                'name':  config['name'],
+                'interest_rate': config['interest_rate'],
+                'compute': config['compute'],
+            })
+
+
+class SaleOrderLineInterest(models.Model):
+    _inherit = 'sale.order.line'
+
+    is_interest =  fields.Boolean('Is Interest',default=False)

+ 33 - 0
models/account_payment_term_type.py

@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields, tools, api
+
+class 	AccountPaymentTermType(models.Model):
+    _name = 'account.payment.term.type'
+
+    name = fields.Char('name')
+    comment = fields.Text('comment')
+    qty_add = fields.Integer('incrementar', help="Indica la cantidad que sera incrementada a la fecha.")
+    type_calculation = fields.Selection([('day', 'Día'),('month','Mes')], default='day', help='Indica la forma que  sera incrementado la fecha  de las cuotas.')
+
+    @api.model
+    def _create_default_type_term(self):
+        term = [
+            {
+                'name': 'Días',
+                'qty_add': 1,
+                'type_calculation': 'day',
+            },{
+                'name': 'Meses',
+                'qty_add': 1,
+                'type_calculation': 'month',
+            }
+        ]
+        for termDefault in term:
+            paymentTerm = self.env['account.payment.term.type'].search([('name', '=', termDefault['name'])])
+            if (not paymentTerm):
+                    self.env['account.payment.term.type'].create({
+                        'name': termDefault['name'],
+                        'qty_add': termDefault['qty_add'],
+                        'type_calculation': termDefault['type_calculation'],
+                    })

+ 51 - 0
models/account_sale_term.py

@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+from openerp import models, fields, tools, api
+import openerp.addons.decimal_precision as dp
+
+class AccountSaleTerm(models.Model):
+    _name = 'account.sale.term'
+
+    '''Sale Interest '''
+    sale_amount = fields.Float('Amount Sale', digits_compute=dp.get_precision('Account'), default=0.0) ## Valor de la Venta
+    sale_payments_init = fields.Float('Amount Payments', digits_compute=dp.get_precision('Account'), default=0.0) ## Payment Initial
+    sale_residual = fields.Float('Amount Residual', digits_compute=dp.get_precision('Account'), default=0.0)##
+    interest_qty = fields.Float('Interés %', digits=(3,6), digits_compute=dp.get_precision('Interest'), help="Interés %")
+    interest_amount = fields.Float('Amount Interest', digits_compute=dp.get_precision('Account'), default=0.0)
+    amount_total = fields.Float('Amount Residual + Interest ', digits_compute=dp.get_precision('Account'), default=0.0)
+    '''Quota'''
+    date_init = fields.Date() ## Date Initial Quota
+    term_type_id = fields.Many2one('account.payment.term.type', string='Invoice', ondelete='restrict', index=True) ## Type term Payments
+    quota_amount = fields.Float('Amount Quota', digits_compute=dp.get_precision('Account'), default=0.0) ## Amount Quota
+    quota_qty = fields.Integer(string='Qty Quota', default=0) ## QTY Quota
+    state = fields.Selection([('draft','Borrador'),('posted', 'Fijado')], default='draft')
+
+    lines = fields.One2many('account.sale.term.line', 'sale_term_id', string='sale term line')
+    sale_id = fields.Many2one('sale.order', string='Sale Orden', ondelete='restrict', index=True)
+
+
+
+class AccountSaleTermLine(models.Model):
+    _name = 'account.sale.term.line'
+
+    sale_term_id = fields.Many2one('account.sale.term', string='Sale term', ondelete='cascade', index=True)
+    sale_id = fields.Many2one('sale.order', string='Sale Orden', ondelete='restrict', index=True)
+
+    number = fields.Integer(string='number', default=0)
+    cuota_number = fields.Char('number Cuota')
+    date = fields.Date()
+    amount = fields.Float('Amount Quota', digits_compute=dp.get_precision('Account'), default=0.0)
+    days = fields.Integer(string='days', default=0)
+    value = fields.Char('Type')
+
+
+class saleOrderTermConfig(models.Model):
+    _inherit = 'sale.order'
+
+    sale_term = fields.One2many('account.sale.term', 'sale_id', string=' Account Interest')
+    sale_term_line = fields.One2many('account.sale.term.line', 'sale_id', string=' Account Interest')
+
+class saleOrderLineTermConfig(models.Model):
+    _inherit = 'sale.order.line'
+
+    is_discount_sale_term =  fields.Boolean('',default=False)
+    amount_line_interest = fields.Float('Amount Interest', digits_compute=dp.get_precision('Account'), default=0.0)

+ 380 - 0
models/eiru_utility_tool_sale.py

@@ -0,0 +1,380 @@
+# -*- coding: utf-8 -*-
+from openerp import api, fields, models
+from openerp.exceptions import except_orm
+from datetime import datetime, timedelta
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+from dateutil.relativedelta import relativedelta
+import math
+
+class saleOrder(models.Model):
+	_inherit = 'sale.order'
+
+	def sale_convert_str_to_datetime(self, date):
+		return datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
+
+	''' Get Sale Order '''
+	@api.model
+	def getSaleOrder(self,idOrder):
+		return[{
+			'id': order.id,
+			'amountTotal': order.amount_total,
+			'dateOrder': order.date_order.split(" ")[0],
+			'currency': {
+				'id': order.pricelist_id.currency_id.id,
+				'symbol': order.pricelist_id.currency_id.symbol,
+				'decimalSeparator': order.pricelist_id.currency_id.decimal_separator,
+				'decimalPlaces': order.pricelist_id.currency_id.decimal_places,
+				'thousandsSeparator': order.pricelist_id.currency_id.thousands_separator,
+			}
+		} for order in self.env['sale.order'].browse(idOrder)]
+
+	''' Get Sale Term '''
+	@api.model
+	def getSaleTerm(self, orderId):
+		return [{
+			'saleAmount': term.sale_amount,
+			'salePaymentsInit': term.sale_payments_init,
+			'saleResidual': term.sale_residual,
+			'interestQty': term.interest_qty,
+			'amountTotal': term.amount_total,
+			'dateInit': term.date_init,
+			'termTypeId': term.term_type_id.id,
+			'quotaAmount': term.quota_amount,
+			'quotaQty': term.quota_qty,
+			'interestAmount': term.interest_amount,
+			'lines': [{
+			    'number': line.number,
+			    'cuotaNumber': line.cuota_number,
+			    'date': line.date,
+			    'amount': line.amount,
+			    'days': line.days,
+			    'value': line.value,
+			}for line in term.lines]
+		}for term in self.env['account.sale.term'].search([('sale_id.id', '=',orderId)])]
+
+	''' Registar entrega Inicial '''
+	@api.model
+	def saleTermUpdatePaymentsInitial(self, orderId, amount):
+		amountPayments = float(amount)
+		qty = 0
+		saleOrder = self.env['sale.order'].browse(orderId)
+		if (not saleOrder):
+			return {
+				'state': False
+			}
+
+		decimalPlaces = saleOrder.pricelist_id.currency_id.decimal_places
+		if (not decimalPlaces):
+			decimalPlaces = 0
+
+		saleResidual = saleOrder.amount_total - amountPayments
+
+		for line in saleOrder.order_line:
+			line.write({
+				'interest_amount': 0,
+				'price_unit': round((line.price_unit - line.amount_line_interest), decimalPlaces),
+				'amount_line_interest': 0
+			})
+
+		'''Eliminar linia de DESCUENTO '''
+		lineDiscount = self.env['sale.order.line'].search([('order_id', '=', saleOrder.id), ('is_discount_sale_term', '=', True)])
+		if (lineDiscount):
+			lineDiscount.unlink()
+
+		term = {
+			'sale_amount': round(saleOrder.amount_total, decimalPlaces),
+			'sale_payments_init': round(amountPayments, decimalPlaces),
+			'sale_residual': round(saleResidual, decimalPlaces),
+			'interest_qty': 0,
+			'interest_amount': 0,
+			'amount_total': round(saleResidual, decimalPlaces),
+			'sale_id': saleOrder.id,
+		}
+
+		saleTerm = self.env['account.sale.term'].search([('sale_id', '=', saleOrder.id)])
+		if (not saleTerm):
+			saleTerm = saleTerm = self.env['account.sale.term'].create(term)
+		else:
+			saleTerm.write(term)
+
+		termLines = self.env['account.sale.term.line'].search([('sale_term_id', '=', saleTerm.id),('sale_id', '=', saleOrder.id)])
+		if(termLines):
+			termLines.unlink()
+
+		return {
+			'state': True,
+		}
+
+	''' Calcular Interes '''
+	@api.model
+	def calculateInterestSale(self, orderId, qty, amountPayments,paymentsFormat):
+		qty = float(qty)
+		amountPayments= float(amountPayments)
+
+		saleOrder = self.env['sale.order'].browse(orderId)
+		if (not saleOrder):
+			return {
+				'state': False
+			}
+
+		decimalPlaces = saleOrder.pricelist_id.currency_id.decimal_places
+		if (not decimalPlaces):
+			decimalPlaces = 0
+
+		for line in saleOrder.order_line:
+			line.write({
+				'interest_amount': 0,
+				'price_unit': round((line.price_unit - line.amount_line_interest), decimalPlaces),
+				'amount_line_interest': 0
+			})
+
+		'''Eliminar linia de DESCUENTO '''
+		lineDiscount = self.env['sale.order.line'].search([('order_id', '=', saleOrder.id), ('is_discount_sale_term', '=', True)])
+		if (lineDiscount):
+			lineDiscount.unlink()
+
+		saleResidual = saleOrder.amount_total - amountPayments
+		amountInterest = round(( saleResidual * (qty / 100)),decimalPlaces)
+		amountDecimal = saleResidual -int(saleResidual)
+		newInterest = amountInterest - amountDecimal if (amountInterest < 0 ) else amountInterest
+		saleTotal = saleResidual + newInterest
+
+		term = {
+			'sale_amount': round(saleOrder.amount_total,decimalPlaces ),
+			'sale_payments_init': round(amountPayments,decimalPlaces),
+			'sale_residual': round(saleResidual,decimalPlaces),
+			'interest_qty': qty,
+			'interest_amount': round(newInterest, decimalPlaces),
+			'amount_total': round(saleTotal, decimalPlaces),
+			'sale_id': saleOrder.id,
+		}
+
+		saleTerm = self.env['account.sale.term'].search([('sale_id', '=', saleOrder.id)])
+		if (not saleTerm):
+			saleTerm = saleTerm = self.env['account.sale.term'].create(term)
+		else:
+			saleTerm.write(term)
+
+		termLines = self.env['account.sale.term.line'].search([('sale_term_id', '=', saleTerm.id),('sale_id', '=', saleOrder.id)])
+		if(termLines):
+			termLines.unlink()
+
+		return {
+			'state':True,
+			'amountInterest': newInterest,
+		}
+
+	''' Calcular Cuota '''
+	@api.model
+	def calculatePaymentTermSaleOrder(self, values):
+		decimal_precision = self.env['decimal.precision'].precision_get('Account')
+		order = self.env['sale.order'].browse(values['orderId'])
+		if (not order):
+			return False
+
+		dateSale = self.sale_convert_str_to_datetime(order.date_order.split(" ")[0])
+		datefirst = self.sale_convert_str_to_datetime(values['dateInit'])
+		amountOrder = order.amount_total
+
+		termSale = self.env['account.sale.term'].search([('sale_id', '=', values['orderId'])])
+		if(termSale):
+			amountOrder += termSale.interest_amount
+
+
+		amountTotal = round(float(amountOrder), decimal_precision)
+		amountPayments  = round(float(values['amountPayments']), decimal_precision)
+		amountResidual = round(float(amountTotal - amountPayments), decimal_precision)
+		amountCuota = round(float(values['amountCuota']), decimal_precision)
+		cuotaCant = values['qtyCuota']
+
+		if (values['qtyCuota'] > 0):
+			amountCuota = round(float(amountResidual /values['qtyCuota']), decimal_precision)
+
+		if(values['amountCuota'] > 0):
+			cuotaCant = (amountResidual /values['amountCuota'])
+
+		if (amountPayments > 0):
+			cuotaCant +=1
+
+		termCalculator = []
+
+		cuotasCalc =  math.modf(round(cuotaCant,decimal_precision))
+		cuotaTotal = int(cuotasCalc[1])
+		if (cuotasCalc[0] >= 0.1):
+			cuotaTotal	+= 1
+
+		termType = self.env['account.payment.term.type'].browse(values['typeTerm'])
+		if (not termType):
+			return False
+
+
+		numberCuota = 0
+		for cuota in xrange(int(cuotaCant)):
+			numberCuota = cuota+1
+			amount = amountCuota
+			adddaysMaturity = datefirst - dateSale
+			date = datefirst
+
+			if (numberCuota == 1 and (amountPayments > 0)):
+				amount = amountPayments
+				if (adddaysMaturity.days > 0):
+					adddaysMaturity = dateSale - dateSale
+				date = dateSale
+
+			if (numberCuota >= cuotaTotal):
+				amount = amountTotal
+
+			amountTotal -= amount
+
+			termCalculator.append({
+				'number' : numberCuota,
+				'cuotaNumber': str(numberCuota)+"/"+str(cuotaTotal),
+				'date': date.strftime(DEFAULT_SERVER_DATE_FORMAT),
+				'amount': amount,
+				'days': adddaysMaturity.days,
+				'value': 'fixed' if (numberCuota < cuotaTotal) else 'balance'
+			})
+
+			days = datefirst - dateSale
+			if(numberCuota == 1 and (amountPayments > 0) and days.days > 0 ):
+				continue
+
+			if (termType.type_calculation == 'month' ):
+				datefirst += relativedelta(months=termType.qty_add)
+			else :
+				datefirst += timedelta(days=termType.qty_add)
+
+		if (amountTotal > 0 ):
+			numberCuota +=1
+			adddaysMaturity = datefirst - dateSale
+
+			termCalculator.append({
+				'number' : numberCuota,
+				'cuotaNumber': str(numberCuota)+"/"+str(cuotaTotal),
+				'date': datefirst.strftime(DEFAULT_SERVER_DATE_FORMAT),
+				'amount': amountTotal,
+				'days': adddaysMaturity.days,
+				'value': 'fixed' if (numberCuota < cuotaTotal) else 'balance'
+			})
+
+		termLines = self.env['account.sale.term.line'].search([('sale_id', '=', values['orderId'])])
+		if(termLines):
+			termLines.unlink()
+
+		linesTerm= []
+		for line in termCalculator:
+			linesTerm.append([0,False,{
+				'sale_id': values['orderId'],
+				'number': line['number'],
+				'cuota_number': line['cuotaNumber'],
+				'date': line['date'],
+				'amount': line['amount'],
+				'days': line['days'],
+				'value': line['value'],
+			}])
+
+		saleTerm = {
+			'date_init': values['dateInit'],
+			'term_type_id': values['typeTerm'],
+			'quota_amount': values['amountCuota'],
+			'quota_qty': values['qtyCuota'],
+			'lines': linesTerm,
+		}
+
+		if (not termSale):
+			termSale.create(saleTerm)
+		else:
+			termSale.write(saleTerm)
+
+		return termCalculator
+
+	''' Payments Term '''
+	@api.model
+	def accountPaymentTermConfiguratorSale(self, values, orderId):
+		resUser = self.env.user
+		if (not resUser):
+			return {
+				'state': False,
+				'message': 'No fue posible localizar el usuario.'
+			}
+
+		saleTerm = self.env['account.sale.term'].search([('sale_id', '=', orderId)])
+		if (not saleTerm):
+			return {
+				'state': False,
+				'message': 'No fue posible localizar Termino de pago configurable.'
+			}
+
+		saleOrder = self.env['sale.order'].browse(orderId)
+		if (not saleOrder):
+			return {
+				'state': False,
+				'message': 'No fue posible localizar el numero de orden.'
+			}
+
+		decimalPlaces = saleOrder.pricelist_id.currency_id.decimal_places
+		if (not decimalPlaces):
+			decimalPlaces = 0
+
+		''' Actualizar el interes por item '''
+		for line in saleOrder.order_line:
+			line.write({
+				'interest_amount': saleTerm.interest_qty,
+				'amount_line_interest':round((line.price_unit * (saleTerm.interest_qty / 100)), decimalPlaces),
+				'price_unit': round((line.price_unit * (1 + (saleTerm.interest_qty / 100))), decimalPlaces),
+			})
+
+		'''Eliminar linia de DESCUENTO '''
+		lineDiscount = self.env['sale.order.line'].search([('order_id', '=', saleOrder.id), ('is_discount_sale_term', '=', True)])
+		if (lineDiscount):
+			lineDiscount.unlink()
+
+		''' Crear el descuento por la entrega inicial'''
+		if (saleTerm.interest_qty > 0 and saleTerm.sale_payments_init > 0 ):
+			interestLine = {
+				'order_id': saleOrder.id,
+				'name': "Amortización de interés por entrega inicial de %s" %(saleTerm.sale_payments_init),
+				'price_unit': -round((saleTerm.sale_payments_init * (saleTerm.interest_qty / 100)), decimalPlaces),
+				'price_subtotal': -round((saleTerm.sale_payments_init * (saleTerm.interest_qty / 100)), decimalPlaces),
+				'is_discount_sale_term': True,
+			}
+			line = self.env['sale.order.line'].create(interestLine)
+
+
+		'''consultar sale term line'''
+		saleTermLine = self.env['account.sale.term.line'].search([('sale_id', '=', orderId)])
+		if (not saleTermLine):
+			return {
+				'state': False,
+				'message': 'No fue posible localizar la configuracion de las cuota.'
+			}
+
+		'''Eliminar las linea del termino de pago'''
+		term = self.env['account.payment.term'].search([('config', '=', True),('user_term', '=', resUser.id),('type_operation', '=', 'sale')])
+		if (term):
+			term.unlink()
+
+		line = []
+		for configTerm in saleTermLine:
+			line.append([0,False,{
+				'value': configTerm.value,
+				'days': configTerm.days,
+				'value_amount': configTerm.amount if (configTerm.value == 'fixed') else  0
+			}])
+
+		term = self.env['account.payment.term'].create({
+			'name': 'Plazos Configurables %s - %s'%('Ventas', resUser.name),
+			'type_operation': 'sale',
+			'user_term': resUser.id,
+			'config': True,
+			'line_ids': line,
+		})
+
+		''' Actualizar condiciones de pago en la venta '''
+		saleOrder.write({'payment_term': term.id})
+
+		saleTerm.write({'state': 'posted'})
+		return {
+			'state': True,
+			'message': 'Condiciones de pago configurado con éxito'
+		}

+ 13 - 0
models/payment_term_configurator.py

@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+from openerp import api, fields, models
+from openerp.exceptions import except_orm
+from datetime import datetime, timedelta
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+from dateutil.relativedelta import relativedelta
+
+class AccountPaymentTerm(models.Model):
+	_inherit = 'account.payment.term'
+
+	config = fields.Boolean(default='False')
+	type_operation = fields.Selection([('all', 'Todo'),('sale','Venta'),('purchase', 'Compra')],'Tipo de operacion', default='all', help='Define si el plazo de pago puede sera utilizado por Ventas, Compras o Todos')
+	user_term = fields.Many2one('res.users', 'user')

+ 145 - 0
models/purchase_order_term_configurator.py

@@ -0,0 +1,145 @@
+# -*- coding: utf-8 -*-
+from openerp import api, fields, models
+from openerp.exceptions import except_orm
+from datetime import datetime, timedelta
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+from dateutil.relativedelta import relativedelta
+
+class PurchaseOrder (models.Model):
+	_inherit = 'purchase.order'
+
+	date_quota = fields.Date("Fecha de la primera cuota")
+
+	def sale_convert_str_to_datetime(self, date):
+		return datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
+
+	''' Get Purchase '''
+	@api.model
+	def getPurchaseOrder(self,idOrder):
+		return[{
+			'id': order.id,
+			'amountTotal': order.amount_total,
+			'dateOrder': order.date_order.split(" ")[0],
+			'dateQuota': order.date_quota or order.date_order.split(" ")[0],
+			'currency': {
+				'id': order.pricelist_id.currency_id.id,
+				'symbol': order.pricelist_id.currency_id.symbol,
+				'decimalSeparator': order.pricelist_id.currency_id.decimal_separator,
+				'decimalPlaces': order.pricelist_id.currency_id.decimal_places,
+				'thousandsSeparator': order.pricelist_id.currency_id.thousands_separator,
+			}
+		} for order in self.env['purchase.order'].browse(idOrder)]
+
+	''' CALCULATOR '''
+	@api.model
+	def calculatePaymentTermPurchaseOrder(self, values):
+		order = self.env['purchase.order'].browse(values['orderId'])
+
+		if (not order):
+			return False
+
+		dateSale = self.sale_convert_str_to_datetime(order.date_order.split(" ")[0])
+		datefirst = self.sale_convert_str_to_datetime(order.date_quota or order.date_order.split(" ")[0])
+
+		amountTotal = order.amount_total
+		amountPayments  = values['amountPayments']
+		amountResidual = amountTotal - amountPayments
+		cuotaCant = (amountResidual /values['amountCuota'])
+
+		if (amountPayments > 0):
+			cuotaCant +=1
+
+		termCalculator = []
+		cuotaTotal= int(cuotaCant) if ((cuotaCant - int(cuotaCant)) <= 0) else int(cuotaCant)+1
+		termType = self.env['account.payment.term.type'].browse(values['typeTerm'])
+		if (not termType):
+			return False
+
+		numberCuota = 0
+		for cuota in xrange(int(cuotaCant)):
+			numberCuota = cuota+1
+			amount = values['amountCuota']
+			adddaysMaturity = datefirst - dateSale
+			date = datefirst
+
+			if (numberCuota == 1 and (amountPayments > 0)):
+				amount = amountPayments
+				if (adddaysMaturity.days > 0):
+					adddaysMaturity = dateSale - dateSale
+				date = dateSale
+
+			amountTotal -= amount
+			termCalculator.append({
+				'number' : numberCuota,
+				'cuotaNumber': str(numberCuota)+"/"+str(cuotaTotal),
+				'date': date.strftime(DEFAULT_SERVER_DATE_FORMAT),
+				'amount': amount,
+				'days': adddaysMaturity.days,
+				'value': 'fixed' if (numberCuota < cuotaTotal) else 'balance'
+			})
+
+			days = datefirst - dateSale
+			if(numberCuota == 1 and (amountPayments > 0) and days.days > 0 ):
+				continue
+
+			if (termType.type_calculation == 'month' ):
+				datefirst += relativedelta(months=termType.qty_add)
+			else :
+				datefirst += timedelta(days=termType.qty_add)
+
+
+		if (amountTotal > 0 ):
+			numberCuota +=1
+			adddaysMaturity = datefirst - dateSale
+
+			termCalculator.append({
+				'number' : numberCuota,
+				'cuotaNumber': str(numberCuota)+"/"+str(cuotaTotal),
+				'date': datefirst.strftime(DEFAULT_SERVER_DATE_FORMAT),
+				'amount': amountTotal,
+				'days': adddaysMaturity.days,
+				'value': 'fixed' if (numberCuota < cuotaTotal) else 'balance'
+			})
+
+		return termCalculator
+
+	''' Config Term '''
+	@api.model
+	def accountPaymentTermConfigurator(self, values, orderId):
+		resUser = self.env.user
+		if (not resUser):
+			return {
+				'state': False,
+				'message': 'No fue posible localizar el usuario.'
+			}
+
+		term = self.env['account.payment.term'].search([('config', '=', True),('user_term', '=', resUser.id),('type_operation', '=', 'purchase')])
+		if (term):
+			term.unlink()
+
+		line = []
+		for configTerm in values:
+			line.append([0,False,{
+				'payment_id': term.id,
+				'value': configTerm['value'],
+				'days': configTerm['days'],
+				'value_amount': - configTerm['amount'] if (configTerm['value'] == 'fixed') else  0
+			}])
+
+		term = self.env['account.payment.term'].create({
+			'name': 'Plazos Configurables %s - %s'%('Compras', resUser.name),
+			'type_operation': 'purchase',
+			'user_term': resUser.id,
+			'config': True,
+			'line_ids': line,
+		})
+
+		''' Actualizar condiciones de pago en la purchase '''
+		order = self.env['purchase.order'].browse(orderId)
+		if (order):
+			order.write({'payment_term_id': term.id})
+
+		return {
+			'state': True,
+			'message': 'Condiciones de pago configurado con éxito'
+		}

+ 5 - 0
security/ir.model.access.csv

@@ -0,0 +1,5 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+account_payment_term_type_from,account.payment.term.type,model_account_payment_term_type,base.group_sale_manager,1,1,1,1
+accont_payments_term_config_from,accont.payments.term.config,model_accont_payments_term_config,base.group_sale_manager,1,1,1,1
+account_sale_term,account.sale.term,model_account_sale_term,base.group_sale_manager,1,1,1,1
+account_sale_term_line,account.sale.term.line,model_account_sale_term_line,base.group_sale_manager,1,1,1,1

BIN
static/description/icon.png


+ 165 - 0
static/src/css/style.css

@@ -0,0 +1,165 @@
+
+@media (min-width: 768px){
+    .expired-account-modal .modal-lg {
+        width: 800px !important;
+    }
+}
+/* loading */
+.widget-content.widget-loading-eiru-utility-tool {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    color : #000;
+    display: none;
+    z-index: 1100;
+    background: #8080806b;
+    align-items: center;
+    justify-content: center;
+}
+/* HEADER */
+.eiru-utility-tool-header {
+    font-size: 12pt;
+    padding-bottom: 10px;
+    padding-top: 10px;
+}
+.eiru-utility-tool-from-label {
+    width: 150px;
+    height: 30px;
+    font-size: 14px;
+    padding-top: 5px;
+    padding-left: 5px;
+}
+.label-interes {
+    width: 70px !important;
+}
+.eiru-utility-tool-from-group-input {
+    width: calc(100% - 150px);
+    height: 30px;
+    padding-left: 5px;
+    padding-right: 5px;
+    float: right;
+}
+.input-interes {
+    width: calc(100% - 70px) !important;
+
+}
+.eiru-utility-tool-input-currency {
+    width: calc(100% - 30px);
+    height: 30px;
+    float: left;
+    font-size: 12pt;
+    text-align: right;
+}
+.eiru-utility-tool-symbol-currency {
+    width: 30px;
+    height: 30px;
+    float: right;
+    text-align: center;
+    font-size: 13pt;
+    border: 1px solid #ccc;
+    background: #e3e3e3;
+}
+.eiru-utility-tool-button-interes {
+    height: 30px;
+    width: 90% !important;
+    font-weight: bold;
+}
+.eiru-utility-tool-hr {
+    width: calc(50% - 60px);
+    margin-top: 10px;
+    margin-bottom: 5px;
+    border-color: #9e9e9e;
+}
+.float-left {
+    float: left;
+    margin-left: 10px;
+}
+.float-right {
+    float: right;
+    margin-right: 10px;
+}
+.eiru-utility-tool-hr-title {
+    width: 100px;
+    float: left;
+    font-weight: bold;
+    text-align: center;
+    font-size: 11pt;
+    color: #9e9e9e
+}
+/*____________ TABLE _____________*/
+.eiru-utility-tool-table {
+     margin-top: 0px !important;
+ }
+.expired-account-modal .modal-head-wrapper-eiru-utility-tool {
+     width: 100%;
+}
+.expired-account-modal .modal-item-term-configurator {
+    width: 100%;
+    height: 176px;
+    overflow-y: auto;
+}
+
+/* Table Header */
+.expired-account-modal .eiru-utility-tool-table table thead tr {
+    height: 40px !important;
+}
+.expired-account-modal .eiru-utility-tool-table table thead tr th:nth-child(1){
+    width: 137px;
+    text-align: center;
+    font-size: 12pt;
+    font-weight: bold;
+}
+.expired-account-modal .eiru-utility-tool-table table thead tr th:nth-child(2){
+    width: 300px;
+    font-size: 12pt;
+    font-weight: bold;
+}
+.expired-account-modal .eiru-utility-tool-table table thead tr th:nth-child(3){
+    width: 300px;
+    font-size: 12pt;
+    font-weight: bold;
+}
+
+/* TBODY */
+.expired-account-modal .eiru-utility-tool-table table tbody tr {
+    height: 35px;
+}
+.expired-account-modal .eiru-utility-tool-table table tbody tr td:nth-child(1) {
+    width: 137px;
+    font-size: 12pt;
+    padding-left: 10px;
+    padding-top: 8px;
+    text-align: center;
+}
+
+.expired-account-modal .eiru-utility-tool-table table tbody tr td:nth-child(2) {
+    width: 294px;
+    font-size: 12pt;
+    padding-left: 10px;
+    padding-top: 8px;
+}
+.expired-account-modal .eiru-utility-tool-table table tbody tr td:nth-child(3) {
+    width: 279px;
+    font-size: 12pt;
+    padding-right: 25px;
+    padding-top: 8px;
+    text-align: right;
+}
+/*---------------------
+        Button
+------------------------*/
+.eiru-utility-tool-footer {
+    padding-top: 10px;
+    padding-bottom: 10px;
+}
+.eiru-utility-tool-button {
+    font-size: 12pt !important;
+    width: 130px;
+    height: 35px;
+}
+/* bottom CALCULAR */
+.term-configurator-button-calculator{
+    margin-left: 30px !important;
+    margin-top: 10px !important;
+    margin-bottom: 10px !important;
+}

+ 359 - 0
static/src/js/eiru_payment_term_configurator_purchase.js

@@ -0,0 +1,359 @@
+(function() {
+
+    openerp.widgetInstancePaymentTermPurchase = null;
+    openerp.parentInstancePaymentTermPurchase = null;
+    var Qweb = openerp.web.qweb;
+    var instance = openerp;
+    var instanceWeb = openerp.web;
+
+    openerp.PaymentTermPurchase = instance.Widget.extend({
+        template: 'eiruPaymentTerm.Purchase',
+
+        id: undefined,
+        order: [],
+        calculatorTerm: [],
+        termType: [],
+
+        /************
+        |   INIT    |
+        ************/
+        init: function(parent) {
+            this._super(parent);
+            this.buttons = parent.$buttons;
+        },
+
+        /************
+        |   START   |
+        ************/
+        start: function() {
+            var self = this;
+            this.$el.click(function() {
+                self.fectchInitial();
+            });
+            self.buttons.click(function(e) {
+                /* E (Editar) */
+                if (e.target.accessKey === 'E')
+                    self.$el.css('display','none');
+                /* S (Guarrdar) */
+                if (e.target.accessKey === 'S')
+                    self.$el.css('display','flex');
+                /* D (Cancelar) */
+                if (e.target.accessKey === 'D')
+                    self.$el.css('display','flex');
+                /* CREAR */
+                if (e.target.accessKey === 'C')
+                    self.$el.css('display','none');
+            });
+        },
+
+        /*===============
+        |   ID ORDER    |
+        ===============*/
+        updateId: function(id) {
+            var self = this;
+            self.id = id;
+
+            self.$el.css('display','flex');
+            if (!id)
+                self.$el.css('display','none');
+        },
+
+        /*=====================
+        |   Remover Modal     |
+        =====================*/
+        removeModal: function() {
+            $('.expired-account-modal').remove();
+            $('.modal-backdrop').remove();
+        },
+
+        /*===============================
+        |       Recargar la Pagina      |
+        ===============================*/
+        reloadPage: function() {
+            openerp.parentInstancePaymentTermPurchase.reload();
+        },
+
+        /******************************
+        ||       Metodo Inicial      ||
+        ******************************/
+        fectchInitial: function() {
+            var self = this;
+
+            self.fetchPurchaseOrder(self.id).then(function(order) {
+                return order;
+            }).then(function(order) {
+                self.order = order;
+                return self.fetchTypeTerm();
+            }).then(function(termType) {
+                self.termType = termType;
+                return self.showTaskSelected();
+            });
+        },
+
+        /*===============================
+        |       GET Purchase Order      |
+        ===============================*/
+        fetchPurchaseOrder: function(id) {
+            var order = new openerp.web.Model('purchase.order');
+            return order.call('getPurchaseOrder',[id],{
+                context: new openerp.web.CompoundContext()
+            });
+        },
+
+        /*=========================================
+        |     GET  Tipo de condicion de pagos     |
+        =========================================*/
+        fetchTypeTerm: function() {
+            var typeTerm = new openerp.web.Model('account.payment.term.type');
+            return typeTerm.query(['id','name']).all()
+        },
+
+        /*===================
+        |       Modal       |
+        ===================*/
+        showTaskSelected: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var state = true;
+            /*Curency Order*/
+            var saleOrder = self.order[0];
+            var currencyOrder = saleOrder.currency;
+            /*term type */
+            var typeTerm = self.termType;
+
+            if (!typeTerm.length){
+                instanceWeb.notification.do_warn("Atencion", "No existe tipo de condiciones de pagos.");
+                return ;
+            }
+            typeTerm.unshift({"id": '', 'name': ''})
+
+            /* Modal */
+            var modal = Qweb.render('eiruPaymentTerm.ModalConfigurator', {'termTypes':typeTerm});
+            $('.openerp_webclient_container').after(modal);
+            $('.expired-account-modal').modal();
+
+            var amountSale = $('.expired-account-modal').find('.amount-sale');
+            var symbolCurrency = $('.expired-account-modal').find('.symbol-currency');
+
+            var initialpayments = $('.expired-account-modal').find('.initial-payments-amount');
+            var amountResidual = $('.expired-account-modal').find('.amount-residual');
+
+            var dateSale = $('.expired-account-modal').find('.date-sale');
+            var dateQuota = $('.expired-account-modal').find('.date-quota');
+            var typeTerm = $('.expired-account-modal').find('.term-select');
+            var amountQuota = $('.expired-account-modal').find('.amount-quota');
+            /* Bottom Calcular */
+            var bottomCalcular = $('.expired-account-modal').find('.bt-calular');
+            /* table */
+            var tableRow = $('.expired-account-modal').find('.table-tbody');
+            /*Bottom Guardar */
+            buttonAccept = $('.expired-account-modal').find('.button-accept');
+            /* Value initial */
+            amountSale.val(instanceWeb.formatCurrency(saleOrder.amountTotal, currencyOrder));
+            amountResidual.val(instanceWeb.formatCurrency(saleOrder.amountTotal, currencyOrder));
+
+            symbolCurrency.text(currencyOrder.symbol);
+            dateSale.val(moment(saleOrder.dateOrder).format('DD/MM/YYYY'));
+            dateQuota.val(moment(saleOrder.dateQuota).format('DD/MM/YYYY'));
+
+            /*******************************
+            *  FOCUSIN initialpayments     *
+            *******************************/
+            initialpayments.focusin(function(e){
+                var amount = instanceWeb.unFormatCurrency(initialpayments.val());
+                if (amount === 0)
+                    initialpayments.val('');
+            });
+            /****************************
+            *   KEYUP initialpayments   *
+            ****************************/
+            initialpayments.keyup(function(e) {
+                var amountPayments = instanceWeb.unFormatCurrency(initialpayments.val());
+                var saleAmount = instanceWeb.unFormatCurrency(amountSale.val());
+                if (e.key === currencyOrder.decimalSeparator && currencyOrder.decimalPlaces > 0)
+                    return false ;
+
+                initialpayments.val(instanceWeb.formatCurrency(amountPayments, currencyOrder));
+                amountResidual.val(instanceWeb.formatCurrency((saleAmount - amountPayments), currencyOrder))
+
+            });
+            /********************************
+            *    FOCUS OUT initialpayments  *
+            ********************************/
+            initialpayments.focusout(function(e) {
+                var saleAmount = instanceWeb.unFormatCurrency(amountSale.val());
+                var amount = instanceWeb.unFormatCurrency(initialpayments.val());
+
+                if (amount > saleAmount) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la entrega supera el valor de la venta.");
+                    initialpayments.focus();
+                    return false;
+                }
+                amountResidual.val(instanceWeb.formatCurrency((saleAmount - amount), currencyOrder))
+            });
+
+            /*--------------------------
+                FOCUSIN amountQuota
+            ----------------------------*/
+            amountQuota.focusin(function(e) {
+                var amount = instanceWeb.unFormatCurrency( amountQuota.val());
+                if (amount === 0)
+                     amountQuota.val('');
+            });
+            /*-----------------------
+                KEYUP amountQuota
+            ------------------------*/
+            amountQuota.keyup(function(e) {
+                if (e.key === currencyOrder.decimalSeparator && currencyOrder.decimalPlaces > 0)
+                    return false ;
+
+                cuotaAmount = instanceWeb.unFormatCurrency(amountQuota.val());
+                amountQuota.val(instanceWeb.formatCurrency(cuotaAmount, currencyOrder));
+
+            });
+            /*---------------------------
+                FOCUS OUT amountQuota
+            ----------------------------*/
+            amountQuota.focusout(function(e) {
+                var saleAmount = instanceWeb.unFormatCurrency(amountSale.val());
+                var amountPayments = instanceWeb.unFormatCurrency(initialpayments.val());
+                var amount = instanceWeb.unFormatCurrency(amountQuota.val());
+
+                if (amount <= 0) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la cuota debe de ser mayor que cero.");
+                    amountQuota.focus();
+                    return false;
+                }
+
+                if (amount > (saleAmount - amountPayments)) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la cuota no puede superar el valor total de la venta.\nVenta ="+saleAmount+"\nEntrega ="+amountPayments+"\nCuota = "+amount);
+                    amountQuota.focus();
+                    return false;
+                }
+            });
+            /*-------------------
+                CLICK CALCULAR
+            ---------------------*/
+            bottomCalcular.click(function(e) {
+                tableRow.find('tr').remove();
+                var htmlLine = '';
+                var cuotaAmount = instanceWeb.unFormatCurrency(amountQuota.val());
+                var amountPayments = instanceWeb.unFormatCurrency(initialpayments.val());
+                /* */
+                if(!typeTerm.val()) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes de Seleccionar el tipo de plazo de pago.");
+                    typeTerm.focus();
+                    return;
+                }
+                /* */
+                if (cuotaAmount <= 0) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la cuota debe de ser mayor que cero.");
+                    amountQuota.focus();
+                    return;
+                }
+
+                var termSale = {
+                    'orderId': self.id,
+                    'typeTerm': parseInt(typeTerm.val().trim()),
+                    'amountCuota': cuotaAmount,
+                    'amountPayments': amountPayments,
+                }
+
+                /* GENERAR LA LISTA DE CUOTA */
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.calculatePaymentTerm(termSale).then(function(calculatorTerm) {
+                    return calculatorTerm;
+                }).then(function(calculatorTerm) {
+                    self.calculatorTerm = calculatorTerm;
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                    if (!!calculatorTerm.length) {
+                        _.each(calculatorTerm, function(line) {
+                           var dateMaturity = moment(line.date).format('DD/MM/YYYY');
+                           var amount = instanceWeb.formatCurrency(line.amount, currencyOrder) +" "+currencyOrder.symbol;
+                            htmlLine +='<tr><td><span>'+line.cuotaNumber+'</span></td><td><span>'+dateMaturity+'</span></td><td><span>'+amount+'</span></td></tr>';
+                        })
+                        tableRow.append(htmlLine);
+                    }
+                });
+            });
+            /*----------------------
+                ACEPTAR / GUARDAR
+            ----------------------*/
+            buttonAccept.click(function(e) {
+                if (!self.calculatorTerm.length) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes de calcular las cuota antes de guardar.");
+                    return ;
+                }
+
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.accountPaymentTermConfigurator(self.calculatorTerm, self.id).then(function(termConfigurator) {
+                    return termConfigurator;
+                }).then(function(termConfigurator) {
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                    self.removeModal(e);
+                    state = termConfigurator.state;
+                    self.reloadPage();
+                });
+
+                defer.resolve(state);
+            });
+            /*-----------
+                CERRAR
+            -----------*/
+            $('.expired-account-modal').on('hidden.bs.modal', function (e) {
+                defer.resolve(false);
+                self.removeModal(e);
+            });
+
+            return defer;
+        },
+        /*----------------------
+            CALCULATOR TERM
+        ----------------------*/
+        calculatePaymentTerm: function(values) {
+            var order = new instance.web.Model('purchase.order');
+            return order.call('calculatePaymentTermPurchaseOrder',[values], {
+                context: new instance.web.CompoundContext()
+            });
+        },
+        /* --------------------------------------
+            Create / writer - Term Paymen
+        ---------------------------------------- */
+        accountPaymentTermConfigurator: function(values, id){
+            var term = new instance.web.Model('purchase.order');
+            return term.call('accountPaymentTermConfigurator',[values, id], {
+                context: new instance.web.CompoundContext()
+            });
+        }
+    });
+
+    if (instance.web && instance.web.FormView) {
+        instance.web.FormView.include({
+            load_record: function(record) {
+                this._super.apply(this, arguments);
+
+                if (this.model !== 'purchase.order')
+                    return;
+
+                openerp.parentInstancePaymentTermPurchase = this;
+
+                if (openerp.widgetInstancePaymentTermPurchase) {
+                    openerp.widgetInstancePaymentTermPurchase.updateId(record.id);
+                    if (this.$el.find('.button-term-configurator-purchase').length !== 0){
+                        return
+                    }
+                }
+
+                if (this.$el.find('.button-term-configurator-purchase').length !== 0 )
+                    return;
+
+                openerp.widgetInstancePaymentTermPurchase = new openerp.PaymentTermPurchase(this);
+                var elemento = this.$el.find('.oe_form').find('.purchase-payment-term-configurator');
+
+                openerp.widgetInstancePaymentTermPurchase.appendTo(elemento);
+                openerp.widgetInstancePaymentTermPurchase.updateId(record.id);
+            },
+
+        });
+    }
+})();

+ 517 - 0
static/src/js/eiru_utility_tool_sale.js

@@ -0,0 +1,517 @@
+(function() {
+
+    openerp.widgetInstanceEiruUtilityToolSale = null;
+    openerp.parentInstanceEiruUtilityToolSale = null;
+    var Qweb = openerp.web.qweb;
+    var instance = openerp;
+    var instanceWeb = openerp.web;
+
+    openerp.EiruUtilityToolSale = instance.Widget.extend({
+        template: 'EiruUtilityTool.Sale',
+
+        id: undefined,
+        order: [],
+        calculatorTerm: [],
+        termType: [],
+        accountSaleTerm: [],
+
+        /************
+        |   INIT    |
+        ************/
+        init: function(parent) {
+            this._super(parent);
+            this.buttons = parent.$buttons;
+        },
+
+        /************
+        |   START   |
+        ************/
+        start: function() {
+            var self = this;
+            this.$el.click(function() {
+                self.fectchInitial();
+            });
+            self.buttons.click(function(e) {
+                /* E (Editar) */
+                if (e.target.accessKey === 'E')
+                    self.$el.css('display','none');
+                /* S (Guarrdar) */
+                if (e.target.accessKey === 'S')
+                    self.$el.css('display','flex');
+                /* D (Cancelar) */
+                if (e.target.accessKey === 'D')
+                    self.$el.css('display','flex');
+                /* CREAR */
+                if (e.target.accessKey === 'C')
+                    self.$el.css('display','none');
+            });
+        },
+
+        /*===============
+        |   ID ORDER    |
+        ===============*/
+        updateId: function(id) {
+            var self = this;
+            self.id = id;
+
+            self.$el.css('display','flex');
+            if (!id)
+                self.$el.css('display','none');
+        },
+        /*=====================
+        |   Remover Modal     |
+        =====================*/
+        removeModal: function() {
+            $('.expired-account-modal').remove();
+            $('.modal-backdrop').remove();
+        },
+        /*===============================
+        |       Recargar la Pagina      |
+        ===============================*/
+        reloadPage: function() {
+            openerp.parentInstanceEiruUtilityToolSale.reload();
+        },
+        /******************************
+        ||       Metodo Inicial      ||
+        ******************************/
+        fectchInitial: function() {
+            var self = this;
+            self.fetchSaleOrder(self.id).then(function(order) {
+                return order;
+            }).then(function(order) {
+                self.order = order;
+                return self.fetchTypeTerm();
+            }).then(function(termType) {
+                self.termType = termType;
+                return self.fetchTermSale(self.id);
+            }).then(function(accountSaleTerm) {
+                self.accountSaleTerm = accountSaleTerm;
+                console.log(accountSaleTerm);
+                return self.showModal();
+            });
+        },
+        /*===============================
+        |       GET Order      |
+        ===============================*/
+        fetchSaleOrder: function(id) {
+            var order = new openerp.web.Model('sale.order');
+            return order.call('getSaleOrder',[id],{
+                context: new openerp.web.CompoundContext()
+            });
+        },
+        /*===============================
+        |       GET Sale term           |
+        ===============================*/
+        fetchTermSale: function(id) {
+            var order = new openerp.web.Model('sale.order');
+            return order.call('getSaleTerm',[id],{
+                context: new openerp.web.CompoundContext()
+            });
+        },
+        /*=========================================
+        |     GET  Tipo de condicion de pagos     |
+        =========================================*/
+        fetchTypeTerm: function() {
+            var typeTerm = new openerp.web.Model('account.payment.term.type');
+            return typeTerm.query(['id','name']).all()
+        },
+        /*===================
+        |       Modal       |
+        ===================*/
+        showModal: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var state = true;
+            /*Curency Order*/
+            var saleOrder = self.order[0];
+            var accountSaleTerm = self.accountSaleTerm[0];
+            var currencyOrder = saleOrder.currency;
+            // /*term type */
+            var numberFormat = {
+                'decimalSeparator': ',',
+                'decimalPlaces': 0,
+                'thousandsSeparator': '.'
+            }
+            var interstFormat = {
+                'decimalSeparator': ',',
+                'decimalPlaces': 2,
+                'thousandsSeparator': '.'
+            }
+
+            var typeTerm = self.termType;
+            if (!typeTerm.length){
+                instanceWeb.notification.do_warn("Atencion", "No existe tipo de condiciones de pagos.");
+                return ;
+            }
+            typeTerm.unshift({"id": '', 'name': ''})
+
+            /* Modal */
+            var modal = Qweb.render('EiruUtilityTool.SaleModal',{'termTypes':typeTerm});
+            $('.openerp_webclient_container').after(modal);
+            $('.expired-account-modal').modal();
+
+            var amountOrder = $('.expired-account-modal').find('.amount-order'); //Valor de la orden.
+            var symbolCurrency = $('.expired-account-modal').find('.symbol-currency'); //Symbolo de moneda.
+            var dateSale = $('.expired-account-modal').find('.date-sale'); //Fecha de venta.
+
+            var initialPaymentsAmount = $('.expired-account-modal').find('.initial-payments-amount'); //Valor de Entrega.
+            var amountResidual = $('.expired-account-modal').find('.amount-residual'); //Valor Residual (Venta - Entrega).
+
+            var interestQty = $('.expired-account-modal').find('.interest-qty'); // % de interest.
+            var amountInterest = $('.expired-account-modal').find('.amount-interest'); //Total Interest.
+            var btInterestCalc = $('.expired-account-modal').find('.bt-interest-calc'); //Botton CALCULAR Interest.
+
+            var amountFinal = $('.expired-account-modal').find('.amount-final'); //Valor final (residual + interest).
+
+            var dateQuotaInit = $('.expired-account-modal').find('.date-quota-init'); //Fecha de Primera Cuota.
+            var termSelect = $('.expired-account-modal').find('.term-select'); //Termino de Pago.
+            var amountQuota = $('.expired-account-modal').find('.amount-quota'); //Valor de Cuota.
+            var qtyQuota = $('.expired-account-modal').find('.qty-quota'); //Cantidad de Cuota.
+            var btQuotaCalc = $('.expired-account-modal').find('.bt-quota-calc'); //Calcular Cuotas.
+
+            var tableRow = $('.expired-account-modal').find('.table-tbody'); //Table.
+
+            var buttonAccept = $('.expired-account-modal').find('.button-accept'); //
+
+            /*###### Data INIT ###############################################*/
+            amountOrder.val(instanceWeb.formatCurrency(saleOrder.amountTotal, currencyOrder));
+            amountResidual.val(instanceWeb.formatCurrency(saleOrder.amountTotal, currencyOrder));
+            amountFinal.val(instanceWeb.formatCurrency(saleOrder.amountTotal, currencyOrder));
+            symbolCurrency.text(currencyOrder.symbol);
+            dateSale.val(moment(saleOrder.dateOrder).format("YYYY-MM-DD"));
+            dateQuotaInit.val(moment(saleOrder.dateOrder).format("YYYY-MM-DD"));
+
+            /*######## SALE TERM    ##########################################*/
+            if (!!accountSaleTerm) {
+                amountOrder.val(instanceWeb.formatCurrency(accountSaleTerm.saleAmount, currencyOrder));
+                initialPaymentsAmount.val(instanceWeb.formatCurrency(accountSaleTerm.salePaymentsInit, currencyOrder));
+                amountResidual.val(instanceWeb.formatCurrency(accountSaleTerm.saleResidual, currencyOrder));
+
+                interestQty.val(instanceWeb.formatCurrency(accountSaleTerm.interestQty, interstFormat));
+
+                amountInterest.val(instanceWeb.formatCurrency(accountSaleTerm.interestAmount, currencyOrder));
+                amountFinal.val(instanceWeb.formatCurrency(accountSaleTerm.amountTotal, currencyOrder));
+
+                dateQuotaInit.val(!!accountSaleTerm.dateInit ?accountSaleTerm.dateInit :moment(saleOrder.dateOrder).format("YYYY-MM-DD"))
+                termSelect.val(accountSaleTerm.termTypeId)
+                amountQuota.val(instanceWeb.formatCurrency(accountSaleTerm.quotaAmount, currencyOrder));
+                qtyQuota.val(instanceWeb.formatCurrency(accountSaleTerm.quotaQty, numberFormat));
+
+                tableRow.find('tr').remove();
+                var htmlLine = '';
+                self.calculatorTerm = accountSaleTerm.lines
+
+                _.each(self.calculatorTerm, function(line) {
+                   var dateMaturity = moment(line.date).format('DD/MM/YYYY');
+                   var amount = instanceWeb.formatCurrency(line.amount, currencyOrder) +" "+currencyOrder.symbol;
+                    htmlLine +='<tr><td><span>'+line.cuotaNumber+'</span></td><td><span>'+dateMaturity+'</span></td><td><span>'+amount+'</span></td></tr>';
+                })
+                tableRow.append(htmlLine);
+            }
+            /*###### FOCUSIN initialPaymentsAmount  ##########################*/
+            initialPaymentsAmount.focusin(function(e){
+                var amount = instanceWeb.unFormatCurrency(initialPaymentsAmount.val());
+                if (amount === 0)
+                    initialPaymentsAmount.val('');
+            });
+            initialPaymentsAmount.keyup(function(e) {
+                var amountPayments = instanceWeb.unFormatCurrency(initialPaymentsAmount.val());
+                var saleAmount = instanceWeb.unFormatCurrency(amountOrder.val());
+                if (e.key === currencyOrder.decimalSeparator && currencyOrder.decimalPlaces > 0)
+                    return false ;
+
+                initialPaymentsAmount.val(instanceWeb.formatCurrency(amountPayments, currencyOrder));
+                amountResidual.val(instanceWeb.formatCurrency((saleAmount - amountPayments), currencyOrder))
+                amountFinal.val(instanceWeb.formatCurrency((saleAmount - amountPayments), currencyOrder))
+                interestQty.val(0)
+                amountInterest.val(0)
+            });
+            initialPaymentsAmount.focusout(function(e) {
+                var saleAmount = instanceWeb.unFormatCurrency(amountOrder.val());
+                var amount = instanceWeb.unFormatCurrency(initialPaymentsAmount.val());
+
+                if (amount > saleAmount) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la entrega supera el valor de la venta.");
+                    initialPaymentsAmount.focus();
+                    return false;
+                }
+
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.saleTermPaymentsInitial(amount).then(function(paymentsUpdate) {
+                    return paymentsUpdate;
+                }).then(function(paymentsUpdate) {
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                });
+
+                amountResidual.val(instanceWeb.formatCurrency((saleAmount - amount), currencyOrder))
+                amountFinal.val(instanceWeb.formatCurrency((saleAmount - amount), currencyOrder))
+
+                interestQty.val(0)
+                amountInterest.val(0)
+                amountQuota.val(0)
+                qtyQuota.val(0)
+                self.calculatorTerm = [];
+                tableRow.find('tr').remove();
+            });
+
+            /*###### interestQty focusin #####################################*/
+            interestQty.focusin(function(e) {
+                var values = instanceWeb.unFormatCurrency(interestQty.val());
+                if (values === 0)
+                    interestQty.val('');
+            });
+            interestQty.keyup(function(e) {
+                var qtyInterest = instanceWeb.unFormatCurrency(interestQty.val());
+                if (e.key === interstFormat.decimalSeparator && interstFormat.decimalPlaces > 0)
+                    return false ;
+
+                interestQty.val(instanceWeb.formatCurrency(qtyInterest, interstFormat));
+            });
+            interestQty.focusout(function(e) {
+                amountQuota.val(0)
+                qtyQuota.val(0)
+                calculatorTerm = []
+                tableRow.find('tr').remove();
+            })
+            /*###### CLICK btInterestCalc  ###################################*/
+            btInterestCalc.click(function(e) {
+                var interest = instanceWeb.unFormatCurrency(interestQty.val());
+                var residual = instanceWeb.unFormatCurrency(amountResidual.val());
+                var paymentsAmount = instanceWeb.unFormatCurrency(initialPaymentsAmount.val());
+
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.calculateInterest(interest, paymentsAmount, instanceWeb.formatCurrency(paymentsAmount, interstFormat)).then(function(interestcalc) {
+                    return interestcalc;
+                }).then(function(interestcalc) {
+                    amountInterest.val(0)
+                    amountFinal.val(instanceWeb.formatCurrency(residual, currencyOrder))
+                    amountQuota.val(0)
+                    qtyQuota.val(0)
+                    calculatorTerm = []
+                    tableRow.find('tr').remove();
+
+                    if (interestcalc.state) {
+                        amountInterest.val(instanceWeb.formatCurrency(interestcalc.amountInterest, currencyOrder))
+                        amountFinal.val(instanceWeb.formatCurrency(residual + interestcalc.amountInterest, currencyOrder))
+                    }
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                });
+            });
+            /*######  VALOR DE LA CUOTA ######################################*/
+            amountQuota.focusin(function(e) {
+                var amount = instanceWeb.unFormatCurrency( amountQuota.val());
+                if (amount === 0) {
+                    amountQuota.val('');
+                    qtyQuota.removeAttr("disabled");
+                }
+            });
+            amountQuota.keyup(function(e) {
+                qtyQuota.attr("disabled", true);
+                if (e.key === currencyOrder.decimalSeparator && currencyOrder.decimalPlaces > 0)
+                    return false ;
+
+                cuotaAmount = instanceWeb.unFormatCurrency(amountQuota.val());
+                amountQuota.val(instanceWeb.formatCurrency(cuotaAmount, currencyOrder));
+            });
+            amountQuota.focusout(function(e) {
+                var saleAmount = instanceWeb.unFormatCurrency(amountFinal.val());
+                var amount = instanceWeb.unFormatCurrency(amountQuota.val());
+
+                if (amount <= 0) {
+                    amountQuota.val('0');
+                    qtyQuota.removeAttr("disabled");
+                    qtyQuota.focus();
+                }
+                if (amount > (saleAmount)) {
+                    instanceWeb.notification.do_warn("Atencion", "El valor de la cuota no puede superar el Saldo.\nSaldo ="+saleAmount+"\nCuota = "+amount);
+                    amountQuota.focus();
+                    return false;
+                }
+            });
+            /*###### CANTIDAD DE CUOTA #######################################*/
+            qtyQuota.focusin(function(e){
+                var qty = instanceWeb.unFormatCurrency( qtyQuota.val());
+                if (qty === 0){
+                    amountQuota.removeAttr("disabled");
+                    qtyQuota.val('');
+                }
+            });
+            qtyQuota.keyup(function(e) {
+                amountQuota.attr("disabled", true);
+                if (e.key === numberFormat.decimalSeparator && numberFormat.decimalPlaces > 0)
+                    return false ;
+
+                cuotaAmount = instanceWeb.unFormatCurrency(qtyQuota.val());
+                qtyQuota.val(instanceWeb.formatCurrency(cuotaAmount, numberFormat));
+            });
+            qtyQuota.focusout(function(e) {
+                var qty = instanceWeb.unFormatCurrency(qtyQuota.val());
+
+                if (qty <= 0) {
+                    qtyQuota.val('0');
+                    amountQuota.removeAttr("disabled");
+                    amountQuota.focus();
+                }
+            });
+            /*###### GENERAR CUOTAS ##########################################*/
+            btQuotaCalc.click(function(e) {
+                tableRow.find('tr').remove();
+                var htmlLine = '';
+
+                var finalAmount = instanceWeb.unFormatCurrency(amountFinal.val());
+                var quotaAmount = instanceWeb.unFormatCurrency(amountQuota.val());
+                var quotaQty = instanceWeb.unFormatCurrency(qtyQuota.val());
+                var amountPayments = instanceWeb.unFormatCurrency(initialPaymentsAmount.val());
+
+
+                if (!dateQuotaInit.val()) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes ingresa la fecha de la primera cuota.");
+                    dateQuotaInit.focus();
+                    return;
+                }
+
+                if(!termSelect.val()) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes de Seleccionar el tipo de plazo de pago.");
+                    termSelect.focus();
+                    return;
+                }
+
+                if (quotaAmount > finalAmount) {
+                    instanceWeb.notification.do_warn("Atencion", "EL valor de la cuota no puede superar el valor del saldo.");
+                    quotaAmount.focus();
+                    return;
+                }
+                if (quotaAmount <=0 && quotaQty<= 0){
+                    instanceWeb.notification.do_warn("Atencion", "Debes ingresar un monto o la cantidad de las cuota.");
+                    return;
+                }
+
+                var termSale = {
+                    'orderId': self.id,
+                    'typeTerm': parseInt(termSelect.val().trim()),
+                    'amountCuota': quotaAmount,
+                    'qtyCuota': quotaQty,
+                    'dateInit': dateQuotaInit.val(),
+                    'amountResidual': finalAmount,
+                    'amountPayments':amountPayments,
+                }
+
+                /* GENERAR LA LISTA DE CUOTA */
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.calculatePaymentTerm(termSale).then(function(calculatorTerm) {
+                    return calculatorTerm;
+                }).then(function(calculatorTerm) {
+                    self.calculatorTerm = calculatorTerm;
+                    // console.log(calculatorTerm);
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                    if (!!calculatorTerm.length) {
+                        _.each(calculatorTerm, function(line) {
+                           var dateMaturity = moment(line.date).format('DD/MM/YYYY');
+                           var amount = instanceWeb.formatCurrency(line.amount, currencyOrder) +" "+currencyOrder.symbol;
+                            htmlLine +='<tr><td><span>'+line.cuotaNumber+'</span></td><td><span>'+dateMaturity+'</span></td><td><span>'+amount+'</span></td></tr>';
+                        })
+                        tableRow.append(htmlLine);
+                    }
+                });
+            });
+            /*###### ACEPTAR --> GUARDAR #####################################*/
+            buttonAccept.click(function(e) {
+                if (!self.calculatorTerm.length) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes de calcular las cuota antes de guardar.");
+                    return ;
+                }
+
+                $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','flex');
+                self.accountPaymentTermConfigurator(self.calculatorTerm, self.id).then(function(termConfigurator) {
+                    return termConfigurator;
+                }).then(function(termConfigurator) {
+                    $('.expired-account-modal').find('.widget-content.widget-loading-term-configurator').css('display','none');
+                    self.removeModal(e);
+                    state = termConfigurator.state;
+                    self.reloadPage();
+                });
+
+                defer.resolve(state);
+            });
+
+            /*######   CERRAR      ###########################################*/
+            $('.expired-account-modal').on('hidden.bs.modal', function (e) {
+                defer.resolve(false);
+                self.removeModal(e);
+                self.reloadPage();
+            });
+
+            return defer;
+        },
+        /*===============================
+        |       Calcular interest       |
+        ===============================*/
+        calculateInterest: function(qty, amountPaymenst, paymentsFormat) {
+            var self = this;
+            var order = new instance.web.Model('sale.order');
+            return order.call('calculateInterestSale',[self.id, qty, amountPaymenst, paymentsFormat], {
+                context: new instance.web.CompoundContext()
+            });
+        },
+        /*===========================
+        |   Update Patments Line    |
+        ===========================*/
+        saleTermPaymentsInitial: function(amount) {
+            var self = this;
+            var order = new instance.web.Model('sale.order');
+            return order.call('saleTermUpdatePaymentsInitial',[self.id, amount], {
+                context: new instance.web.CompoundContext()
+            });
+        },
+        /*===========================
+        |       CALCULATOR TERM     |
+        ===========================*/
+        calculatePaymentTerm: function(values) {
+            console.log(values);
+            var order = new instance.web.Model('sale.order');
+            return order.call('calculatePaymentTermSaleOrder',[values], {
+                context: new instance.web.CompoundContext()
+            });
+        },
+        /*===========================================
+        |       Create / writer - Term Paymen       |
+        ===========================================*/
+        accountPaymentTermConfigurator: function(values, id){
+            var term = new instance.web.Model('sale.order');
+            return term.call('accountPaymentTermConfiguratorSale',[values, id], {
+                context: new instance.web.CompoundContext()
+            });
+        }
+    });
+
+    /* INSTANCE*/
+    if (instance.web && instance.web.FormView) {
+        instance.web.FormView.include({
+            load_record: function(record) {
+                this._super.apply(this, arguments);
+
+                if (this.model !== 'sale.order')
+                    return;
+
+                openerp.parentInstanceEiruUtilityToolSale = this;
+
+                if (openerp.widgetInstanceEiruUtilityToolSale) {
+                    openerp.widgetInstanceEiruUtilityToolSale.updateId(record.id);
+                    if (this.$el.find('.bottom-eiru-utility-tool-sale').length !== 0){
+                        return
+                    }
+                }
+
+                if (this.$el.find('.bottom-eiru-utility-tool-sale').length !== 0 )
+                    return;
+
+                openerp.widgetInstanceEiruUtilityToolSale = new openerp.EiruUtilityToolSale(this);
+                var elemento = this.$el.find('.oe_form').find('.eiru-sale-utility-tool-sale');
+
+                openerp.widgetInstanceEiruUtilityToolSale.appendTo(elemento);
+                openerp.widgetInstanceEiruUtilityToolSale.updateId(record.id);
+            },
+
+        });
+    }
+})();

+ 8 - 0
static/src/xml/eiru_payment_term_configurator_purchase.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="eiruPaymentTerm.Purchase">
+        <button type="button" class="button-term-configurator-purchase button-action-term oe_button oe_highlight">
+            Configuración de Cuota
+        </button>
+    </t>
+</template>

+ 8 - 0
static/src/xml/eiru_utility_tool_sale.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="EiruUtilityTool.Sale">
+        <button type="button" class="bottom-eiru-utility-tool-sale oe_button oe_highlight">
+            Configuración de Cuota
+        </button>
+    </t>
+</template>

+ 122 - 0
static/src/xml/modal/modal_eiru_payment_term_configurator.xml

@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="eiruPaymentTerm.ModalConfigurator">
+        <div class="modal in expired-account-modal" tabindex="-1" role="dialog"  data-backdrop="static">
+            <div class="modal-dialog modal-lg" role="document">
+                <div class="modal-content openerp">
+                    <div class="widget-content widget-loading-eiru-utility-tool">
+                        <i class='fa fa-cog fa-spin fa-3x fa-fw'></i>
+                    </div>
+                    <!-- title  -->
+                    <div class="modal-header term-configurator-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close" aria-hidden="true">×</button>
+                        <h3 class="modal-title">Configuración de Cuota</h3>
+                    </div>
+                    <!-- Body -->
+                    <div class="modal-body">
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Valor de Venta</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                  <input type="text" class="form-control eiru-utility-tool-input-currency amount-sale" readonly="readonly" value="0"></input>
+                                  <div class="eiru-utility-tool-symbol-currency">
+                                    <span class="symbol-currency"></span>
+                                  </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Valor de Entrega</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                  <input type="text" class="form-control eiru-utility-tool-input-currency initial-payments-amount" value="0"></input>
+                                  <div class="eiru-utility-tool-symbol-currency">
+                                    <span class="symbol-currency"></span>
+                                  </div>
+                                </div>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Saldo</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                  <input type="text" class="form-control eiru-utility-tool-input-currency amount-residual" readonly="readonly" value="0"></input>
+                                  <div class="eiru-utility-tool-symbol-currency">
+                                    <span class="symbol-currency"></span>
+                                  </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Fecha de venta</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control date-sale" readonly="readonly"></input>
+                                </div>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Fecha Primera Cuota</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control date-quota" readonly="readonly"></input>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Plazo de Pago:</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <select class="form-control term-select">
+                                        <t t-foreach='termTypes' t-as='termType'>
+                                            <option t-attf-value="{{ termType_value.id }}">
+                                                <t t-esc="termType_value.name"/>
+                                            </option>
+                                        </t>
+                                    </select>
+                                </div>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Monto de Cuota</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                  <input type="text" class="form-control eiru-utility-tool-input-currency amount-quota"  value="0"></input>
+                                  <div class="eiru-utility-tool-symbol-currency">
+                                    <span class="symbol-currency"></span>
+                                  </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <button type="button" class="oe_button oe_form_button oe_highlight term-configurator-button-calculator bt-calular">
+                                Calcular
+                            </button>
+                        </div>
+                        <!-- Table -->
+                        <div class="oe_view_manager_body eiru-utility-tool-table">
+                            <div class="modal-head-wrapper-eiru-utility-tool ">
+                                <table class="oe_list_content">
+                                    <thead >
+                                        <tr class="oe_list_header_columns"  >
+                                            <th class="oe_list_header_char oe_sortable">Cuota</th>
+                                            <th class="oe_list_header_char oe_sortable">Vencimiento</th>
+                                            <th class="oe_list_header_char oe_sortable">Valor de la cuota </th>
+                                        </tr>
+                                    </thead>
+                                </table>
+                            </div>
+                            <div class="modal-item-term-configurator">
+                                <table class="oe_list_content">
+                                    <tbody class="table-tbody">
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+
+                    <!-- Pie de Pagina -->
+                    <div class="modal-footer eiru-utility-tool-footer">
+                        <button type="button" class="oe_button oe_form_button oe_highlight button-accept eiru-utility-tool-button ">Guardar</button>
+                        <button type="button" class="oe_button oe_form_button oe_link dismmis-modal eiru-utility-tool-button " data-dismiss="modal">Salir</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </t>
+
+</template>

+ 180 - 0
static/src/xml/modal/modal_eiru_utility_tool_sale.xml

@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="EiruUtilityTool.SaleModal">
+        <div class="modal in expired-account-modal" tabindex="-1" role="dialog"  data-backdrop="static">
+            <div class="modal-dialog modal-lg" role="document">
+                <div class="modal-content openerp">
+                    <div class="widget-content widget-loading-eiru-utility-tool">
+                        <i class='fa fa-cog fa-spin fa-3x fa-fw'></i>
+                    </div>
+
+                    <!-- title  -->
+                    <div class="modal-header eiru-utility-tool-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close" aria-hidden="true">×</button>
+                        <h3 class="modal-title">Configuración de Cuota</h3>
+                    </div>
+
+                    <!-- Body -->
+                    <div class="modal-body">
+                        <!-- Valor de venta  - Fecha de Venta -->
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label"> Valor de Venta</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency amount-order" readonly="readonly" value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Fecha de venta</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="date" class="form-control date-sale"  readonly="readonly"></input>
+                                </div>
+                            </div>
+                        </div>
+
+                        <!-- Valor de Entrega -  Saldo -->
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Valor de Entrega</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency initial-payments-amount" value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Saldo</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency amount-residual" readonly="readonly" value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+
+                        <!-- Interes por cuoata generado -->
+                        <div class="row">
+                            <div class="col-xs-3">
+                                <label class="eiru-utility-tool-from-label label-interes">Interes %</label>
+                                <div class="eiru-utility-tool-from-group-input input-interes">
+                                    <input type="text" maxlength="6" class="form-control eiru-utility-tool-input-currency interest-qty" value="0"></input>
+                                </div>
+                            </div>
+                            <div class="col-xs-3">
+                                <button type="button" class="oe_button oe_form_button oe_highlight eiru-utility-tool-button-interes bt-interest-calc" >
+                                    Calcular Interes
+                                </button>
+                            </div>
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Valor del Interes</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency amount-interest" readonly="readonly" value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Residual + Interes</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency amount-final" readonly="readonly" value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="row">
+                            <hr class="eiru-utility-tool-hr float-left"/>
+                            <div class="eiru-utility-tool-hr-title">Cuotas</div>
+                            <hr class="eiru-utility-tool-hr float-right"/>
+                        </div>
+
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Fecha Inicio </label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="date" class="form-control date-quota-init"></input>
+                                </div>
+                            </div>
+
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Plazo de Pago:</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <select class="form-control term-select">
+                                        <t t-foreach='termTypes' t-as='termType'>
+                                            <option t-attf-value="{{ termType_value.id }}">
+                                                <t t-esc="termType_value.name"/>
+                                            </option>
+                                        </t>
+                                    </select>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="row">
+                            <div class="col-xs-6">
+                                <label class="eiru-utility-tool-from-label">Monto</label>
+                                <div class="eiru-utility-tool-from-group-input">
+                                    <input type="text" class="form-control eiru-utility-tool-input-currency amount-quota"  value="0"></input>
+                                    <div class="eiru-utility-tool-symbol-currency">
+                                        <span class="symbol-currency"></span>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="col-xs-4">
+                                <label class="eiru-utility-tool-from-label label-interes">Cuota</label>
+                                <div class="eiru-utility-tool-from-group-input input-interes">
+                                    <input type="text" maxlength="3" class="form-control eiru-utility-tool-input-currency qty-quota" value="0"></input>
+                                </div>
+                            </div>
+                            <div class="col-xs-2">
+                                <button type="button" class="oe_button oe_form_button oe_highlight eiru-utility-tool-button-interes bt-quota-calc">
+                                    Calcular
+                                </button>
+                            </div>
+                        </div>
+
+                        <!-- Table -->
+                        <div class="oe_view_manager_body eiru-utility-tool-table">
+                            <div class="modal-head-wrapper-eiru-utility-tool">
+                                <table class="oe_list_content">
+                                    <thead >
+                                        <tr class="oe_list_header_columns" >
+                                            <th class="oe_list_header_char oe_sortable">Cuota</th>
+                                            <th class="oe_list_header_char oe_sortable">Vencimiento</th>
+                                            <th class="oe_list_header_char oe_sortable">Valor de la cuota </th>
+                                        </tr>
+                                    </thead>
+                                </table>
+                            </div>
+                            <div class="modal-item-term-configurator">
+                                <table class="oe_list_content">
+                                    <tbody class="table-tbody">
+                                        <tr></tr>
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                    </div>
+
+                    <!-- Pie de Pagina -->
+                    <div class="modal-footer eiru-utility-tool-footer">
+                        <button type="button" class="oe_button oe_form_button oe_highlight button-accept eiru-utility-tool-button">Guardar</button>
+                        <button type="button" class="oe_button oe_form_button oe_link dismmis-modal eiru-utility-tool-button" data-dismiss="modal">Salir</button>
+                    </div>
+
+                </div>
+            </div>
+        </div>
+    </t>
+
+</template>

+ 61 - 0
views/account_payment_term_type.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <function model="account.payment.term.type" name="_create_default_type_term"/>
+        <!-- from -->
+        <record id="eiru_account_payment_term_type_form" model="ir.ui.view">
+            <field name="name">eiru_account_payment_term_type.form</field>
+            <field name="model">account.payment.term.type</field>
+            <field name="arch" type="xml">
+                <form>
+                    <sheet>
+                        <h2>
+                            <field name="name" string="Descripción"/>
+                        </h2>
+                        <group col="2">
+                            <group>
+                                <field name="type_calculation" string="Forma de Calculo"/>
+                            </group>
+                            <group>
+                                <field name="qty_add" string="Cantidad a adicionar"/>
+                            </group>
+                        </group>
+                        <group>
+                            <field name="comment" string="Información Adicional"/>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <!-- Tree -->
+        <record id="eiru_account_payment_term_type_tree" model="ir.ui.view">
+			<field name="name">eiru_account_payment_term_type.tree</field>
+			<field name="model">account.payment.term.type</field>
+			<field name="arch" type="xml">
+				<tree>
+                    <field name="name" string="Descripción"/>
+                    <field name="type_calculation" string="Forma de Calculo"/>
+                    <field name="qty_add" string="Cantidad a adicionar"/>
+				</tree>
+			</field>
+	    </record>
+
+        <!-- Actions  -->
+        <record id="eiru_account_payment_term_type_actions" model="ir.actions.act_window">
+            <field name="name">Configuración de cuota</field>
+            <field name="res_model">account.payment.term.type</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="target">current</field>
+        </record>
+
+        <!-- Menu Item -->
+        <menuitem
+            id="eiru_account_payment_term_type_menu"
+            name="Configuración de cuota"
+            parent="account.menu_finance_configuration"
+            action="eiru_account_payment_term_type_actions"
+            sequence="4"/>
+    </data>
+</openerp>

+ 29 - 0
views/account_sale_term.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+		<record id="account_sale_term_sale" model="ir.ui.view">
+			<field name="name">account_sale_term.sale</field>
+			<field name="model">sale.order</field>
+			<field name="inherit_id" ref="sale.view_order_form"/>
+			<field name="arch" type="xml">
+				<notebook>
+					 <page string="Negociacion de venta">
+						 <group col="1">
+						   <field name="sale_term" nolabel='1'>
+                               <tree colors="red:state=='draft';black:state=='posted'" create='false'>
+								   <field name="sale_amount" string="Valor de Venta"/>
+								   <field name="sale_payments_init" string='Valor de Entrega'/>
+								   <field name="sale_residual" string='Saldo'/>
+								   <field name="interest_qty" string='Interes %' />
+								   <field name="interest_amount" string='Valor del Interes'/>
+								   <field name="amount_total" string='Residual + Interes'/>
+								   <field name="state" string='Estado'/>
+							   </tree>
+						   </field>
+						 </group>
+					 </page>
+				</notebook>
+			</field>
+		</record>
+	</data>
+</openerp>

+ 33 - 0
views/eiru_sale_utility_tool.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+
+		<!-- sale.order -->
+        <record id="eiru_sale_utility_tool_sale" model="ir.ui.view">
+            <field name="name">eiru_sale_utility_tool.sale</field>
+            <field name="model">sale.order</field>
+            <field name="inherit_id" ref="sale.view_order_form"/>
+            <field name="arch" type="xml">
+                <field name="order_line" position="before">
+                    <div class="eiru-sale-utility-tool-sale" attrs="{'invisible': [('state','not in',['draft','sent'])]}"></div>
+                </field>
+            </field>
+        </record>
+
+		<!-- purchase.order -->
+		<record id="views_eiru_payment_term_configurator_purchase" model="ir.ui.view">
+			<field name="name">views_eiru_payment_term_configurator.purchase</field>
+			<field name="model">purchase.order</field>
+			<field name="inherit_id" ref="purchase.purchase_order_form"/>
+			<field name="arch" type="xml">
+				<field name="date_order" position="after">
+					<field name="date_quota" required="1"/>
+				</field>
+				<field name="order_line" position="before">
+					<div class="purchase-payment-term-configurator" attrs="{'invisible': [('state','not in',['draft','sent'])]}"></div>
+				</field>
+			</field>
+		</record>
+
+	</data>
+</openerp>

+ 13 - 0
views/template.xml

@@ -0,0 +1,13 @@
+<openerp>
+    <data>
+        <template id="eiru_sale_utility_tool.eiru_assets" name="eiru_sale_utility_tool_eiru_assets" inherit_id="eiru_assets.assets">
+            <xpath expr="." position="inside">
+                <link rel="stylesheet" href="/eiru_sale_utility_tool/static/src/css/style.css"/>
+                <!-- Sale -->
+                <script type="text/javascript" src="/eiru_sale_utility_tool/static/src/js/eiru_utility_tool_sale.js" />
+                <script type="text/javascript" src="/eiru_sale_utility_tool/static/src/js/eiru_payment_term_configurator_purchase.js" />
+
+            </xpath>
+        </template>
+    </data>
+</openerp>