2018-01-16 06:58:15 +01:00
# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
2018-01-16 06:58:15 +01:00
import time
2018-01-16 11:34:37 +01:00
from flectra import api , fields , models , _
from flectra . addons import decimal_precision as dp
from flectra . exceptions import UserError
2018-01-16 06:58:15 +01:00
class SaleAdvancePaymentInv ( models . TransientModel ) :
_name = " sale.advance.payment.inv "
_description = " Sales Advance Payment Invoice "
@api.model
def _count ( self ) :
return len ( self . _context . get ( ' active_ids ' , [ ] ) )
@api.model
def _get_advance_payment_method ( self ) :
if self . _count ( ) == 1 :
sale_obj = self . env [ ' sale.order ' ]
order = sale_obj . browse ( self . _context . get ( ' active_ids ' ) ) [ 0 ]
if all ( [ line . product_id . invoice_policy == ' order ' for line in order . order_line ] ) or order . invoice_count :
return ' all '
return ' delivered '
@api.model
def _default_product_id ( self ) :
product_id = self . env [ ' ir.config_parameter ' ] . sudo ( ) . get_param ( ' sale.default_deposit_product_id ' )
return self . env [ ' product.product ' ] . browse ( int ( product_id ) )
@api.model
def _default_deposit_account_id ( self ) :
return self . _default_product_id ( ) . property_account_income_id
@api.model
def _default_deposit_taxes_id ( self ) :
return self . _default_product_id ( ) . taxes_id
advance_payment_method = fields . Selection ( [
( ' delivered ' , ' Invoiceable lines ' ) ,
( ' all ' , ' Invoiceable lines (deduct down payments) ' ) ,
( ' percentage ' , ' Down payment (percentage) ' ) ,
( ' fixed ' , ' Down payment (fixed amount) ' )
] , string = ' What do you want to invoice? ' , default = _get_advance_payment_method , required = True )
product_id = fields . Many2one ( ' product.product ' , string = ' Down Payment Product ' , domain = [ ( ' type ' , ' = ' , ' service ' ) ] ,
default = _default_product_id )
count = fields . Integer ( default = _count , string = ' # of Orders ' )
amount = fields . Float ( ' Down Payment Amount ' , digits = dp . get_precision ( ' Account ' ) , help = " The amount to be invoiced in advance, taxes excluded. " )
deposit_account_id = fields . Many2one ( " account.account " , string = " Income Account " , domain = [ ( ' deprecated ' , ' = ' , False ) ] ,
help = " Account used for deposits " , default = _default_deposit_account_id )
deposit_taxes_id = fields . Many2many ( " account.tax " , string = " Customer Taxes " , help = " Taxes used for deposits " , default = _default_deposit_taxes_id )
@api.onchange ( ' advance_payment_method ' )
def onchange_advance_payment_method ( self ) :
if self . advance_payment_method == ' percentage ' :
return { ' value ' : { ' amount ' : 0 } }
return { }
@api.multi
def _create_invoice ( self , order , so_line , amount ) :
inv_obj = self . env [ ' account.invoice ' ]
ir_property_obj = self . env [ ' ir.property ' ]
account_id = False
if self . product_id . id :
account_id = self . product_id . property_account_income_id . id
if not account_id :
inc_acc = ir_property_obj . get ( ' property_account_income_categ_id ' , ' product.category ' )
account_id = order . fiscal_position_id . map_account ( inc_acc ) . id if inc_acc else False
if not account_id :
raise UserError (
_ ( ' There is no income account defined for this product: " %s " . You may have to install a chart of account from Accounting app, settings menu. ' ) %
( self . product_id . name , ) )
if self . amount < = 0.00 :
raise UserError ( _ ( ' The value of the down payment amount must be positive. ' ) )
context = { ' lang ' : order . partner_id . lang }
if self . advance_payment_method == ' percentage ' :
amount = order . amount_untaxed * self . amount / 100
name = _ ( " Down payment of %s %% " ) % ( self . amount , )
else :
amount = self . amount
name = _ ( ' Down Payment ' )
del context
taxes = self . product_id . taxes_id . filtered ( lambda r : not order . company_id or r . company_id == order . company_id )
if order . fiscal_position_id and taxes :
tax_ids = order . fiscal_position_id . map_tax ( taxes ) . ids
else :
tax_ids = taxes . ids
invoice = inv_obj . create ( {
' name ' : order . client_order_ref or order . name ,
' origin ' : order . name ,
' type ' : ' out_invoice ' ,
' reference ' : False ,
' account_id ' : order . partner_id . property_account_receivable_id . id ,
' partner_id ' : order . partner_invoice_id . id ,
' partner_shipping_id ' : order . partner_shipping_id . id ,
' invoice_line_ids ' : [ ( 0 , 0 , {
' name ' : name ,
' origin ' : order . name ,
' account_id ' : account_id ,
' price_unit ' : amount ,
' quantity ' : 1.0 ,
' discount ' : 0.0 ,
' uom_id ' : self . product_id . uom_id . id ,
' product_id ' : self . product_id . id ,
' sale_line_ids ' : [ ( 6 , 0 , [ so_line . id ] ) ] ,
' invoice_line_tax_ids ' : [ ( 6 , 0 , tax_ids ) ] ,
' account_analytic_id ' : order . analytic_account_id . id or False ,
} ) ] ,
' currency_id ' : order . pricelist_id . currency_id . id ,
' payment_term_id ' : order . payment_term_id . id ,
' fiscal_position_id ' : order . fiscal_position_id . id or order . partner_id . property_account_position_id . id ,
' team_id ' : order . team_id . id ,
' user_id ' : order . user_id . id ,
' comment ' : order . note ,
} )
invoice . compute_taxes ( )
invoice . message_post_with_view ( ' mail.message_origin_link ' ,
values = { ' self ' : invoice , ' origin ' : order } ,
subtype_id = self . env . ref ( ' mail.mt_note ' ) . id )
return invoice
@api.multi
def create_invoices ( self ) :
sale_orders = self . env [ ' sale.order ' ] . browse ( self . _context . get ( ' active_ids ' , [ ] ) )
if self . advance_payment_method == ' delivered ' :
sale_orders . action_invoice_create ( )
elif self . advance_payment_method == ' all ' :
sale_orders . action_invoice_create ( final = True )
else :
# Create deposit product if necessary
if not self . product_id :
vals = self . _prepare_deposit_product ( )
self . product_id = self . env [ ' product.product ' ] . create ( vals )
self . env [ ' ir.config_parameter ' ] . sudo ( ) . set_param ( ' sale.default_deposit_product_id ' , self . product_id . id )
sale_line_obj = self . env [ ' sale.order.line ' ]
for order in sale_orders :
if self . advance_payment_method == ' percentage ' :
amount = order . amount_untaxed * self . amount / 100
else :
amount = self . amount
if self . product_id . invoice_policy != ' order ' :
raise UserError ( _ ( ' The product used to invoice a down payment should have an invoice policy set to " Ordered quantities " . Please update your deposit product to be able to create a deposit invoice. ' ) )
if self . product_id . type != ' service ' :
raise UserError ( _ ( " The product used to invoice a down payment should be of type ' Service ' . Please use another product or update this product. " ) )
taxes = self . product_id . taxes_id . filtered ( lambda r : not order . company_id or r . company_id == order . company_id )
if order . fiscal_position_id and taxes :
tax_ids = order . fiscal_position_id . map_tax ( taxes ) . ids
else :
tax_ids = taxes . ids
context = { ' lang ' : order . partner_id . lang }
so_line = sale_line_obj . create ( {
' name ' : _ ( ' Advance: %s ' ) % ( time . strftime ( ' % m % Y ' ) , ) ,
' price_unit ' : amount ,
' product_uom_qty ' : 0.0 ,
' order_id ' : order . id ,
' discount ' : 0.0 ,
' product_uom ' : self . product_id . uom_id . id ,
' product_id ' : self . product_id . id ,
' tax_id ' : [ ( 6 , 0 , tax_ids ) ] ,
' is_downpayment ' : True ,
} )
del context
self . _create_invoice ( order , so_line , amount )
if self . _context . get ( ' open_invoices ' , False ) :
return sale_orders . action_view_invoice ( )
return { ' type ' : ' ir.actions.act_window_close ' }
def _prepare_deposit_product ( self ) :
return {
' name ' : ' Down payment ' ,
' type ' : ' service ' ,
' invoice_policy ' : ' order ' ,
' property_account_income_id ' : self . deposit_account_id . id ,
' taxes_id ' : [ ( 6 , 0 , self . deposit_taxes_id . ids ) ] ,
}