def _get_invoiced(self): # fix de esta funcion porque odoo no lo quiso arreglar # cambiamos != purchase por not in purchase, done precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for order in self: # if order.state != 'purchase': if order.state not in ('purchase', 'done'): order.invoice_status = 'no' continue if any( float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) == -1 for line in order.order_line): order.invoice_status = 'to invoice' elif all( float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) >= 0 for line in order.order_line): order.invoice_status = 'invoiced' else: order.invoice_status = 'no'
def _get_received(self): precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for line in self: # on v9 odoo consider done with no more to purchase, PR has been # deny, if we change it here we should change odoo behaviour on # purchase orders # al final dejamos nuestro criterio porque es confuso para # clientes y de hecho odoo, a diferencia de lo que dice el boton # si te deja crear las facturas en done # if line.state != 'purchase': if line.state not in ('purchase', 'done'): line.delivery_status = 'no' continue if float_compare(line.qty_received, line.product_qty, precision_digits=precision) == -1: line.delivery_status = 'to receive' elif float_compare(line.qty_received, line.product_qty, precision_digits=precision) >= 0: line.delivery_status = 'received' else: line.delivery_status = 'no'
def _get_delivered(self): precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for order in self: if order.state not in ('sale', 'done'): order.delivery_status = 'no' continue if order.manually_set_delivered: order.delivery_status = 'delivered' continue if any( float_compare(line.all_qty_delivered, line.product_uom_qty, precision_digits=precision) == -1 for line in order.order_line): order.delivery_status = 'to deliver' elif all( float_compare(line.all_qty_delivered, line.product_uom_qty, precision_digits=precision) >= 0 for line in order.order_line): order.delivery_status = 'delivered' else: order.delivery_status = 'no'
def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] _logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version')) if data.get('test_ipn'): _logger.warning( 'Received a notification from Paypal using sandbox' ), # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference: invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference)) # check what is buyed if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0: invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees if data.get('mc_currency') != tx.currency_id.name: invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0: invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees)) # check buyer if tx.partner_reference and data.get('payer_id') != tx.partner_reference: invalid_parameters.append(('payer_id', data.get('payer_id'), tx.partner_reference)) # check seller if data.get('receiver_id') and tx.acquirer_id.paypal_seller_account and data['receiver_id'] != tx.acquirer_id.paypal_seller_account: invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account)) if not data.get('receiver_id') or not tx.acquirer_id.paypal_seller_account: # Check receiver_email only if receiver_id was not checked. # In Paypal, this is possible to configure as receiver_email a different email than the business email (the login email) # In Odoo, there is only one field for the Paypal email: the business email. This isn't possible to set a receiver_email # different than the business email. Therefore, if you want such a configuration in your Paypal, you are then obliged to fill # the Merchant ID in the Paypal payment acquirer in Odoo, so the check is performed on this variable instead of the receiver_email. # At least one of the two checks must be done, to avoid fraudsters. if data.get('receiver_email') != tx.acquirer_id.paypal_email_account: invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account)) return invalid_parameters
def action_accept_ready_qty(self): self.with_incidences = False new_moves = [] for move in self.move_lines: if move.state in ('done', 'cancel'): # ignore stock moves cancelled or already done continue precision = move.product_uom.rounding remaining_qty = move.product_uom_qty - move.qty_ready remaining_qty = float_round(remaining_qty, precision_rounding=precision) if float_compare(remaining_qty, 0, precision_rounding=precision) > 0 and \ float_compare(remaining_qty, move.product_qty, precision_rounding=precision) < 0: new_move = move.split(move, remaining_qty) new_moves.append(new_move) if new_moves: new_moves = self.env['stock.move'].browse(new_moves) self._create_backorder(self, backorder_moves=new_moves) new_moves.write({'qty_ready': 0.0}) self.do_unreserve() self.recheck_availability() self.message_post(body=_("User %s accepted ready quantities.") % (self.env.user.name))
def _compute_delivery_status(self): precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for line in self: if line.state not in ('sale', 'done'): line.delivery_status = 'no' continue if line.order_id.manually_set_delivered: line.order_id.delivery_status = 'delivered' continue if float_compare( line.all_qty_delivered, line.product_uom_qty, # line.qty_delivered, line.product_uom_qty, precision_digits=precision) == -1: line.delivery_status = 'to deliver' elif float_compare( line.all_qty_delivered, line.product_uom_qty, # line.qty_delivered, line.product_uom_qty, precision_digits=precision) >= 0: line.delivery_status = 'delivered' else: line.delivery_status = 'no'
def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if data.get('notify_version')[0] != '3.4': _logger.warning( 'Received a notification from Paypal with version %s instead of 2.6. This could lead to issues when managing it.' % data.get('notify_version') ) if data.get('test_ipn'): _logger.warning( 'Received a notification from Paypal using sandbox' ), # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference: invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference)) # check what is buyed if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0: invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees if data.get('mc_currency') != tx.currency_id.name: invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0: invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees)) # check buyer if tx.partner_reference and data.get('payer_id') != tx.partner_reference: invalid_parameters.append(('payer_id', data.get('payer_id'), tx.partner_reference)) # check seller if data.get('receiver_email') != tx.acquirer_id.paypal_email_account: invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account)) if tx.acquirer_id.paypal_seller_account and data.get('receiver_id') != tx.acquirer_id.paypal_seller_account: invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account)) return invalid_parameters
def do_partial(self, cr, uid, ids, context=None): assert len(ids) == 1, 'Partial picking processing may only be done one at a time.' stock_picking = self.pool.get('stock.picking') stock_move = self.pool.get('stock.move') uom_obj = self.pool.get('product.uom') partial = self.browse(cr, uid, ids[0], context=context) partial_data = { 'delivery_date' : partial.date } picking_type = partial.picking_id.type for wizard_line in partial.move_ids: line_uom = wizard_line.product_uom move_id = wizard_line.move_id.id #Quantiny must be Positive if wizard_line.quantity < 0: raise osv.except_osv(_('Warning!'), _('Please provide proper Quantity.')) #Compute the quantity for respective wizard_line in the line uom (this jsut do the rounding if necessary) qty_in_line_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, line_uom.id) if line_uom.factor and line_uom.factor <> 0: if float_compare(qty_in_line_uom, wizard_line.quantity, precision_rounding=line_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The unit of measure rounding does not allow you to ship "%s %s", only roundings of "%s %s" is accepted by the Unit of Measure.') % (wizard_line.quantity, line_uom.name, line_uom.rounding, line_uom.name)) if move_id: #Check rounding Quantity.ex. #picking: 1kg, uom kg rounding = 0.01 (rounding to 10g), #partial delivery: 253g #=> result= refused, as the qty left on picking would be 0.747kg and only 0.75 is accepted by the uom. initial_uom = wizard_line.move_id.product_uom #Compute the quantity for respective wizard_line in the initial uom qty_in_initial_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, initial_uom.id) without_rounding_qty = (wizard_line.quantity / line_uom.factor) * initial_uom.factor if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The rounding of the initial uom does not allow you to ship "%s %s", as it would let a quantity of "%s %s" to ship and only roundings of "%s %s" is accepted by the uom.') % (wizard_line.quantity, line_uom.name, wizard_line.move_id.product_qty - without_rounding_qty, initial_uom.name, initial_uom.rounding, initial_uom.name)) else: seq_obj_name = 'stock.picking.' + picking_type move_id = stock_move.create(cr,uid,{'name' : self.pool.get('ir.sequence').get(cr, uid, seq_obj_name), 'product_id': wizard_line.product_id.id, 'product_qty': wizard_line.quantity, 'product_uom': wizard_line.product_uom.id, 'prodlot_id': wizard_line.prodlot_id.id, 'location_id' : wizard_line.location_id.id, 'location_dest_id' : wizard_line.location_dest_id.id, 'picking_id': partial.picking_id.id, 'employee_id':wizard_line.employee_id.id, },context=context) stock_move.action_confirm(cr, uid, [move_id], context) partial_data['move%s' % (move_id)] = { 'product_id': wizard_line.product_id.id, 'product_qty': wizard_line.quantity, 'product_uom': wizard_line.product_uom.id, 'prodlot_id': wizard_line.prodlot_id.id, 'employee_id':wizard_line.employee_id.id, } if (picking_type == 'in') and (wizard_line.product_id.cost_method == 'average'): partial_data['move%s' % (wizard_line.move_id.id)].update(product_price=wizard_line.cost, product_currency=wizard_line.currency.id) stock_picking.do_partial(cr, uid, [partial.picking_id.id], partial_data, context=context) return {'type': 'ir.actions.act_window_close'}
def interval_min_get(self, cr, uid, id, dt_from, hours, resource=False): """ Calculates the working Schedule from supplied from date to till hours will be satisfied based or resource calendar id. If resource is also given then it will consider the resource leave also and than will calculates resource working schedule @param dt_from: datetime object, start of working scheduled @param hours: float, total number working hours needed scheduled from start date @param resource : Optional Resource id, if supplied than resource leaves will also taken into consideration for calculating working schedule. @return : List datetime object of working schedule based on supplies params """ if not id: td = int(hours) * 3 return [(dt_from - timedelta(hours=td), dt_from)] dt_leave = self._get_leaves(cr, uid, id, resource) dt_leave.reverse() todo = hours result = [] maxrecur = 100 current_hour = dt_from.hour while float_compare(todo, 0, 4) and maxrecur: cr.execute( "select hour_from,hour_to from resource_calendar_attendance where dayofweek='%s' and calendar_id=%s order by hour_from desc", (dt_from.weekday(), id), ) for (hour_from, hour_to) in cr.fetchall(): leave_flag = False if (hour_from < current_hour) and float_compare(todo, 0, 4): m = min(hour_to, current_hour) if (m - hour_from) > todo: hour_from = m - todo dt_check = dt_from.strftime("%Y-%m-%d") for leave in dt_leave: if dt_check == leave: dt_check = datetime.strptime(dt_check, "%Y-%m-%d") + timedelta(days=1) leave_flag = True if leave_flag: break else: d1 = datetime( dt_from.year, dt_from.month, dt_from.day, int(math.floor(hour_from)), int((hour_from % 1) * 60), ) d2 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(m)), int((m % 1) * 60)) result.append((d1, d2)) current_hour = hour_from todo -= m - hour_from dt_from -= timedelta(days=1) current_hour = 24 maxrecur -= 1 result.reverse() return result
def action_accept_ready_qty(self): self.with_incidences = False new_moves = [] for move in self.move_lines: if move.state in ('done', 'cancel'): # ignore stock moves cancelled or already done continue precision = move.product_uom.rounding remaining_qty = move.product_uom_qty - move.qty_ready remaining_qty = float_round(remaining_qty, precision_rounding=precision) if not move.qty_ready: new_moves.append(move.id) elif float_compare(remaining_qty, 0, precision_rounding=precision) > 0 and \ float_compare(remaining_qty, move.product_qty, precision_rounding=precision) < 0: new_move = move.split(move, remaining_qty) new_moves.append(new_move) if new_moves: new_moves = self.env['stock.move'].browse(new_moves) bcko_id = self._create_backorder(self, backorder_moves=new_moves) bck = self.browse(bcko_id) new_moves.write({'qty_ready': 0.0}) self.do_unreserve() self.recheck_availability() self.message_post(body=_("User %s accepted ready quantities.") % (self.env.user.name)) self.action_done() self.date_done = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] _logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version')) if data.get('test_ipn'): _logger.warning( 'Received a notification from Paypal using sandbox' ), # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference: invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference)) # check what is buyed if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0: invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees if data.get('mc_currency') != tx.currency_id.name: invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0: invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees)) # check buyer if tx.payment_method_id and data.get('payer_id') != tx.payment_method_id.acquirer_ref: invalid_parameters.append(('payer_id', data.get('payer_id'), tx.payment_method_id.acquirer_ref)) # check seller if data.get('receiver_id') and tx.acquirer_id.paypal_seller_account and data['receiver_id'] != tx.acquirer_id.paypal_seller_account: invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account)) if not data.get('receiver_id') or not tx.acquirer_id.paypal_seller_account: # Check receiver_email only if receiver_id was not checked. # In Paypal, this is possible to configure as receiver_email a different email than the business email (the login email) # In Odoo, there is only one field for the Paypal email: the business email. This isn't possible to set a receiver_email # different than the business email. Therefore, if you want such a configuration in your Paypal, you are then obliged to fill # the Merchant ID in the Paypal payment acquirer in Odoo, so the check is performed on this variable instead of the receiver_email. # At least one of the two checks must be done, to avoid fraudsters. if data.get('receiver_email') != tx.acquirer_id.paypal_email_account: invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account)) return invalid_parameters
def _do_partial(self, cr, uid, ids, context=None): assert len(ids) == 1, 'Partial picking processing may only be done one at a time.' stock_picking = self.pool.get('stock.picking') stock_move = self.pool.get('stock.move') uom_obj = self.pool.get('product.uom') partial = self.browse(cr, uid, ids[0], context=context) partial_data = { 'delivery_date' : partial.date } picking_type = partial.picking_id.type for wizard_line in partial.move_ids: line_uom = wizard_line.product_uom move_id = wizard_line.move_id.id #Quantiny must be Positive if wizard_line.quantity < 0: raise osv.except_osv(_('Warning!'), _('Please provide proper Quantity.')) #Compute the quantity for respective wizard_line in the line uom (this jsut do the rounding if necessary) qty_in_line_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, line_uom.id) if line_uom.factor and line_uom.factor <> 0: if float_compare(qty_in_line_uom, wizard_line.quantity, precision_rounding=line_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The unit of measure rounding does not allow you to ship "%s %s", only rounding of "%s %s" is accepted by the Unit of Measure.') % (wizard_line.quantity, line_uom.name, line_uom.rounding, line_uom.name)) if move_id: #Check rounding Quantity.ex. #picking: 1kg, uom kg rounding = 0.01 (rounding to 10g), #partial delivery: 253g #=> result= refused, as the qty left on picking would be 0.747kg and only 0.75 is accepted by the uom. initial_uom = wizard_line.move_id.product_uom #Compute the quantity for respective wizard_line in the initial uom qty_in_initial_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.quantity, initial_uom.id) without_rounding_qty = (wizard_line.quantity / line_uom.factor) * initial_uom.factor if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The rounding of the initial uom does not allow you to ship "%s %s", as it would let a quantity of "%s %s" to ship and only rounding of "%s %s" is accepted by the uom.') % (wizard_line.quantity, line_uom.name, wizard_line.move_id.product_qty - without_rounding_qty, initial_uom.name, initial_uom.rounding, initial_uom.name)) else: seq_obj_name = 'stock.picking.' + picking_type move_id = stock_move.create(cr,uid,{'name' : self.pool.get('ir.sequence').get(cr, uid, seq_obj_name), 'product_id': wizard_line.product_id.id, 'product_qty': wizard_line.quantity, 'product_uom': wizard_line.product_uom.id, 'prodlot_id': wizard_line.prodlot_id.id, 'location_id' : wizard_line.location_id.id, 'location_dest_id' : wizard_line.location_dest_id.id, 'picking_id': partial.picking_id.id },context=context) stock_move.action_confirm(cr, uid, [move_id], context) partial_data['move%s' % (move_id)] = { 'product_id': wizard_line.product_id.id, 'product_qty': wizard_line.quantity, 'product_uom': wizard_line.product_uom.id, 'prodlot_id': wizard_line.prodlot_id.id, } if (picking_type == 'in') and (wizard_line.product_id.cost_method == 'average'): partial_data['move%s' % (wizard_line.move_id.id)].update(product_price=wizard_line.cost, product_currency=wizard_line.currency.id) # print "****PARTIAL_DATA********: ", partial_data stock_picking.do_partial(cr, uid, [partial.picking_id.id], partial_data, context=context) return {'type': 'ir.actions.act_window_close'}
def quants_reserve(self, cr, uid, quants, move, link=False, context=None): '''This function reserves quants for the given move (and optionally given link). If the total of quantity reserved is enough, the move's state is also set to 'assigned' :param quants: list of tuple(quant browse record or None, qty to reserve). If None is given as first tuple element, the item will be ignored. Negative quants should not be received as argument :param move: browse record :param link: browse record (stock.move.operation.link) ''' toreserve = [] reserved_availability = move.reserved_availability #split quants if needed for quant, qty in quants: if qty <= 0.0 or (quant and quant.qty <= 0.0): raise osv.except_osv( _('Error!'), _('You can not reserve a negative quantity or a negative quant.' )) if not quant: continue self._quant_split(cr, uid, quant, qty, context=context) toreserve.append(quant.id) reserved_availability += quant.qty #reserve quants if toreserve: self.write( cr, SUPERUSER_ID, toreserve, { 'reservation_id': move.id, 'in_date': datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) }, context=context) #if move has a picking_id, write on that picking that pack_operation might have changed and need to be recomputed if move.picking_id: self.pool.get('stock.picking').write( cr, uid, [move.picking_id.id], {'recompute_pack_op': True}, context=context) #check if move'state needs to be set as 'assigned' rounding = move.product_id.uom_id.rounding if float_compare(reserved_availability, move.product_qty, precision_rounding=rounding) == 0 and move.state in ( 'confirmed', 'waiting'): self.pool.get('stock.move').write(cr, uid, [move.id], {'state': 'assigned'}, context=context) elif float_compare( reserved_availability, 0, precision_rounding=rounding ) > 0 and not move.partially_available: self.pool.get('stock.move').write(cr, uid, [move.id], {'partially_available': True}, context=context)
def interval_min_get(self, cr, uid, id, dt_from, hours, resource=False): """ Calculates the working Schedule from supplied from date to till hours will be satisfied based or resource calendar id. If resource is also given then it will consider the resource leave also and than will calculates resource working schedule @param dt_from: datetime object, start of working scheduled @param hours: float, total number working hours needed scheduled from start date @param resource : Optional Resource id, if supplied than resource leaves will also taken into consideration for calculating working schedule. @return : List datetime object of working schedule based on supplies params """ if not id: td = int(hours) * 3 return [(dt_from - timedelta(hours=td), dt_from)] dt_leave = self._get_leaves(cr, uid, id, resource) dt_leave.reverse() todo = hours result = [] maxrecur = 100 current_hour = dt_from.hour while float_compare(todo, 0, 4) and maxrecur: cr.execute( "select hour_from,hour_to from resource_calendar_attendance where dayofweek='%s' and calendar_id=%s order by hour_from desc", (dt_from.weekday(), id)) for (hour_from, hour_to) in cr.fetchall(): leave_flag = False if (hour_from < current_hour) and float_compare(todo, 0, 4): m = min(hour_to, current_hour) if (m - hour_from) > todo: hour_from = m - todo dt_check = dt_from.strftime('%Y-%m-%d') for leave in dt_leave: if dt_check == leave: dt_check = datetime.strptime( dt_check, '%Y-%m-%d') + timedelta(days=1) leave_flag = True if leave_flag: break else: d1 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(hour_from)), int((hour_from % 1) * 60)) d2 = datetime(dt_from.year, dt_from.month, dt_from.day, int(math.floor(m)), int((m % 1) * 60)) result.append((d1, d2)) current_hour = hour_from todo -= (m - hour_from) dt_from -= timedelta(days=1) current_hour = 24 maxrecur -= 1 result.reverse() return result
def get_quants_line(self, forced_quants_list=False): """ Check if required quantity is available in source location, No multiproduct packs when we are inside this method """ t_quant = self.env['stock.quant'] res = [] line = self[0] # Is called always line by line if forced_quants_list: for quant in forced_quants_list: res.append((quant, quant.qty)) else: if line.product_id: # Move products from a pack or alone line_qty = line.quantity product = line.product_id else: # Move entire packs line_qty = line.package_id.packed_qty # No multiproduct pack product = line.package_id.product_id # No multiproduct pack # Search quants to force the assignament later domain = [('product_id', '=', product.id), ('location_id', '=', line.src_location_id.id), ('package_id', '=', line.package_id.id), ('qty', '>', 0.0)] if line.lot_id: domain.append(('lot_id', '=', line.lot_id.id)) quants_objs = t_quant.search(domain) assigned_qty = 0 rst_qty = line_qty for quant in quants_objs: if float_compare( assigned_qty, line_qty, precision_rounding=product.uom_id.rounding) == -1: #if assigned_qty < line_qty: if float_compare( rst_qty, quant.qty, precision_rounding=product.uom_id.rounding) != -1: #if rst_qty >= quant.qty: res.append((quant, quant.qty)) assigned_qty += quant.qty else: res.append((quant, rst_qty)) assigned_qty += rst_qty rst_qty = line_qty - assigned_qty if float_compare(assigned_qty, line_qty, precision_rounding=product.uom_id.rounding) == -1: #if assigned_qty < line_qty: raise except_orm( _('Error'), _('Not enought stock available\ for product %s, and quantity of \ %s units' % (product.name, line_qty))) return res
def do_transfer(self, cr, uid, picking_ids, context=None): """ If no pack operation, we do simple action_done of the picking Otherwise, do the pack operations """ if not context: context = {} notrack_context = dict(context, mail_notrack=True) stock_move_obj = self.pool.get('stock.move') for picking in self.browse(cr, uid, picking_ids, context=context): if not picking.pack_operation_ids: self.action_done(cr, uid, [picking.id], context=context) continue else: need_rereserve, all_op_processed = self.picking_recompute_remaining_quantities(cr, uid, picking, context=context) #create extra moves in the picking (unexpected product moves coming from pack operations) todo_move_ids = [] if not all_op_processed: todo_move_ids += self._create_extra_moves(cr, uid, picking, context=context) #split move lines if needed toassign_move_ids = [] for move in picking.move_lines: remaining_qty = move.remaining_qty if move.state in ('done', 'cancel'): #ignore stock moves cancelled or already done continue elif move.state == 'draft': toassign_move_ids.append(move.id) if float_compare(remaining_qty, 0, precision_rounding = move.product_id.uom_id.rounding) == 0: if move.state in ('draft', 'assigned', 'confirmed'): todo_move_ids.append(move.id) elif float_compare(remaining_qty,0, precision_rounding = move.product_id.uom_id.rounding) > 0 and \ float_compare(remaining_qty, move.product_qty, precision_rounding = move.product_id.uom_id.rounding) < 0: new_move = stock_move_obj.split(cr, uid, move, remaining_qty, context=notrack_context) todo_move_ids.append(move.id) #Assign move as it was assigned before toassign_move_ids.append(new_move) if need_rereserve or not all_op_processed: if not picking.location_id.usage in ("supplier", "production", "inventory"): self.rereserve_quants(cr, uid, picking, move_ids=todo_move_ids, context=context) self.do_recompute_remaining_quantities(cr, uid, [picking.id], context=context) if todo_move_ids and not context.get('do_only_split'): self.pool.get('stock.move').action_done(cr, uid, todo_move_ids, context=notrack_context) elif context.get('do_only_split'): context = dict(context, split=todo_move_ids) backorder_id = self._create_backorder(cr, uid, picking, context=context) if toassign_move_ids: stock_move_obj.action_assign(cr, uid, toassign_move_ids, context=context) picking_obj = self.pool.get("stock.picking") picking_id = picking_obj.browse(cr, uid, backorder_id) if picking_id: if picking_id.state not in ('done', 'cancel'): self.do_unreserve(cr, uid, picking_id.id, context=context) return True
def get_purchase_line_procurements(self, first_proc, seller, order_by, force_domain=None): """Returns procurements that must be integrated in the same purchase order line as first_proc, by taking all procurements of the same product as first_proc between the date of first proc and date_end. """ frame = seller.order_group_period date_end = False if frame and frame.period_type: date_end = fields.Datetime.to_string( frame.get_date_end_period( fields.Datetime.from_string(first_proc.date_planned))) domain_procurements = [('product_id', '=', first_proc.product_id.id), ('location_id', '=', first_proc.location_id.id), ('company_id', '=', first_proc.company_id.id), ('date_planned', '>=', first_proc.date_planned) ] + (force_domain or []) if first_proc.rule_id.picking_type_id: domain_procurements += [('rule_id.picking_type_id', '=', first_proc.rule_id.picking_type_id.id)] domain_max_date = date_end and [('date_planned', '<', date_end)] or [] procurements_grouping_period = self.search(domain_procurements + domain_max_date, order=order_by) line_qty_product_uom = sum([ self.env['product.uom']._compute_qty(proc.product_uom.id, proc.product_qty, proc.product_id.uom_id.id) for proc in procurements_grouping_period ]) suppliers = first_proc.product_id.seller_ids. \ filtered(lambda supplier: supplier.name == self._get_product_supplier(first_proc)) moq = suppliers and suppliers[0].min_qty or False if moq and float_compare( line_qty_product_uom, moq, precision_rounding=first_proc.product_id.uom_id.rounding) < 0: procurements_after_period = self.search( domain_procurements + [('id', 'not in', procurements_grouping_period.ids)], order=order_by) for proc in procurements_after_period: proc_qty_product_uom = self.env['product.uom']. \ _compute_qty(proc.product_uom.id, proc.product_qty, proc.product_id.uom_id.id) if float_compare(line_qty_product_uom + proc_qty_product_uom, moq, precision_rounding=proc.product_id.uom_id. rounding) > 0: break procurements_grouping_period |= proc line_qty_product_uom += proc_qty_product_uom return self.search([('id', 'in', procurements_grouping_period.ids)], order=order_by)
def action_apply_all(self, cr, uid, ids, context=None): """ Ejecuta la entrega de todos los movimientos del pedido """ date = time.strftime('%Y-%m-%d %H:%M:%S') rline_obj = self.pool.get('delivery.route.line') picking_obj = self.pool.get('stock.picking') move_obj = self.pool.get('stock.move') uom_obj = self.pool.get('product.uom') # Obtiene la informacion del wizard data = self.browse(cr, uid, ids[0], context=context) partial_data = { 'delivery_date' : date } picking_type = data.picking_id.type # Recorre las lineas a entregar for wizard_line in data.line_ids: line_uom = wizard_line.product_uom move_id = wizard_line.move_id.id # Valida que haya un movimiento relacionado if not move_id: continue # Valida que la cantidad de la linea del pedido no sea negativo if wizard_line.product_qty < 0: raise osv.except_osv(_('Warning!'), _('No puede hacer entregas de productos sobre cantidades negativas.')) # Calcula la cantidad del producto en base a la unidad de medida base qty_in_line_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.product_qty, line_uom.id) # Valida el factor de la linea if line_uom.factor and line_uom.factor != 0: if float_compare(qty_in_line_uom, wizard_line.product_qty, precision_rounding=line_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('La unidad de redondeo medida no permite que usted envíe "%s %s", solo redondeo de "%s %s" es aceptado por la unidad de medida.') % (wizard_line.product_qty, line_uom.name, line_uom.rounding, line_uom.name)) # Valida que el movimiento no este entregado if wizard_line.move_id.state != 'done': initial_uom = wizard_line.move_id.product_uom #Compute the quantity for respective wizard_line in the initial uom qty_in_initial_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.product_qty, initial_uom.id) without_rounding_qty = (wizard_line.product_qty / line_uom.factor) * initial_uom.factor if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('La unidad de redondeo medida no permite que usted envíe "%s %s", solo redondeo de "%s %s" es aceptado por la unidad de medida.') % (wizard_line.product_qty, line_uom.name, line_uom.rounding, line_uom.name)) # Agrega la informacion del producto a entregar partial_data['move%s' % (move_id)] = { 'product_id': wizard_line.product_id.id or False, 'product_qty': wizard_line.product_qty, 'product_uom': wizard_line.product_uom.id or False, 'prodlot_id': wizard_line.move_id.prodlot_id.id or False, } # Aplica la salida de almacen sobre los productos a entregar picking_obj.do_partial(cr, uid, [data.picking_id.id], partial_data, context=context) # Indica que la linea fue entregada rline_obj.write(cr, uid, [data.route_line_id.id], {'delivered': True}, context=context) # Pone la linea de la ruta como entregado rline_obj.action_done(cr, uid, [data.route_line_id.id], context=context) return {'type': 'ir.actions.act_window_close'}
def do_partial(self, cr, uid, ids, context=None): requestion_lines= [] request = context.get('request', False) wf_service = netsvc.LocalService("workflow") if request: assert len(ids) == 1, 'request product processing may only be done one at a time.' requestion_obj = self.pool.get('purchase.requisition') uom_obj = self.pool.get('product.uom') partial = self.browse(cr, uid, ids[0], context=context) for wizard_line in self.pool.get('stock.picking').browse(cr,uid,[partial.picking_id.id])[0].move_lines: line_uom = wizard_line.product_uom move_id = wizard_line.id #Quantiny must be Positive if wizard_line.product_qty < 0: raise osv.except_osv(_('Warning!'), _('Please provide proper Quantity.')) #Compute the quantity for respective wizard_line in the line uom (this jsut do the rounding if necessary) qty_in_line_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.product_qty, line_uom.id) if line_uom.factor and line_uom.factor <> 0: if float_compare(qty_in_line_uom, wizard_line.product_qty, precision_rounding=line_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The unit of measure rounding does not allow you to ship "%s %s", only rounding of "%s %s" is accepted by the Unit of Measure.') % (wizard_line.product_qty, line_uom.name, line_uom.rounding, line_uom.name)) if move_id: initial_uom = wizard_line.product_uom qty_in_initial_uom = uom_obj._compute_qty(cr, uid, line_uom.id, wizard_line.product_qty, initial_uom.id) without_rounding_qty = (wizard_line.product_qty / line_uom.factor) * initial_uom.factor if float_compare(qty_in_initial_uom, without_rounding_qty, precision_rounding=initial_uom.rounding) != 0: raise osv.except_osv(_('Warning!'), _('The rounding of the initial uom does not allow you to ship "%s %s", as it would let a quantity of "%s %s" to ship and only rounding of "%s %s" is accepted by the uom.') % (wizard_line.product_qty, line_uom.name, wizard_line.product_qty - without_rounding_qty, initial_uom.name, initial_uom.rounding, initial_uom.name)) line = {'name': wizard_line.name, 'product_id': wizard_line.product_id.id, 'product_qty': wizard_line.product_qty, 'product_uom_id': wizard_line.product_uom.id, } requestion_lines.append((0, 0, line)) if requestion_lines: if partial.picking_id.purchase_requisition_id: raise osv.except_osv(_('Duplication!'), _('You are Already Created Purchase Requisition Before "%s" ') % (partial.picking_id.purchase_requisition_id.name) ) requestion_id = requestion_obj.create(cr, uid , { 'origin': partial.picking_id.name, 'department_id': partial.picking_id.department_id.id, 'category_id':partial.picking_id.category_id.id, 'line_ids': requestion_lines}, context = context) self.pool.get('stock.picking').write( cr, uid, partial.picking_id.id, {'purchase_requisition_id' : requestion_id}) wf_service.trg_validate(uid, 'purchase.requisition', requestion_id, 'draft_to_approve', cr) else: return super(stock_partial_picking, self).do_partial(cr, uid, ids, context=context) return {'type': 'ir.actions.act_window_close'}
def _check_split_possible(self, done_procs_qty): """ Raises error if it is impossible to split the purchase order line. """ prec = self.line_id.product_uom.rounding self.ensure_one() if self.env.context.get('active_ids') and len( self.env.context.get('active_ids')) > 1: raise exceptions.except_orm(_('Error!'), _("Please split lines one by one")) else: if float_compare(self.qty, 0, precision_rounding=prec) <= 0: raise exceptions.except_orm( _('Error!'), _("Impossible to split a negative or null quantity")) if self.line_id.state not in ['draft', 'confirmed']: raise exceptions.except_orm( _('Error!'), _("Impossible to split line which is not in state draft or " "confirmed")) if self.line_id.state == 'draft': if float_compare(self.qty, self.line_id.product_qty, precision_rounding=prec) >= 0: raise exceptions.except_orm( _('Error!'), _("Please choose a lower quantity to split")) if float_compare(self.qty, done_procs_qty, precision_rounding=prec) < 0: raise exceptions.except_orm( _('Error!'), _("Please choose a lower quantity to split")) if self.line_id.state == 'confirmed': _sum = sum([ x.product_qty for x in self.line_id.move_ids if x.state == 'done' ]) _sum_pol_uom = self.env['product.uom']._compute_qty( self.line_id.product_id.uom_id.id, _sum, self.line_id.product_uom.id) if self.qty < _sum_pol_uom: raise exceptions.except_orm( _('Error!'), _("Impossible to split a move in state done")) not_cancelled_qty = sum([ m.product_qty for m in self.line_id.move_ids if m.state != 'cancel' ]) not_cancelled_qty_pol_uom = self.env['product.uom']._compute_qty( self.line_id.product_id.uom_id.id, not_cancelled_qty, self.line_id.product_uom.id) if self.qty >= not_cancelled_qty_pol_uom: raise exceptions.except_orm( _('Error!'), _("Please choose a lower quantity to split"))
def _release_fiscal_budget(self, fiscalyear, released_amount): """ Distribute budget released to all AG of the same year by distribute to the first AG first, show warning if released amount > planned amout """ # Not current year, no budget release allowed current_fy = self.env['account.fiscalyear'].find() release_external_budget = fiscalyear.control_ext_charge_only for project in self.sudo(): if project.current_fy_release_only and current_fy != fiscalyear.id: raise ValidationError( _('Not allow to release budget for fiscalyear %s!\nOnly ' 'current year budget is allowed.' % fiscalyear.name)) budget_plans = project.budget_plan_ids.filtered( lambda l: l.fiscalyear_id == fiscalyear) budget_monitor = project.monitor_expense_ids.filtered( lambda l: l.fiscalyear_id == fiscalyear and l.budget_method == 'expense' and l.charge_type == 'external') budget_plans.write({'released_amount': 0.0}) # Set zero if release_external_budget: # Only for external charge budget_plans = budget_plans.\ filtered(lambda l: l.charge_type == 'external') if not budget_plans: raise ValidationError( _('Not allow to release budget for project without plan!')) planned_amount = sum([x.planned_amount for x in budget_plans]) consumed_amount = sum([x.amount_consumed for x in budget_monitor]) if float_compare(released_amount, planned_amount, 2) == 1: raise ValidationError( _('Releasing budget (%s) > planned (%s)!' % ('{:,.2f}'.format(released_amount), '{:,.2f}'.format(planned_amount)))) if float_compare(released_amount, consumed_amount, 2) == -1: raise ValidationError( _('Releasing budget (%s) < Consumed Amount (%s)!' % ('{:,.2f}'.format(released_amount), '{:,.2f}'.format(consumed_amount)))) remaining = released_amount update_vals = [] for budget_plan in budget_plans: if float_compare(remaining, budget_plan.planned_amount, 2) == 1: update = {'released_amount': budget_plan.planned_amount} remaining -= budget_plan.planned_amount update_vals.append((1, budget_plan.id, update)) else: update = {'released_amount': remaining} remaining = 0.0 update_vals.append((1, budget_plan.id, update)) break if update_vals: project.write({'budget_plan_ids': update_vals}) return True
def _create_negative_clearing_line(self, expense, invoice): # Use invoice line first advance_expense = expense.advance_expense_id if advance_expense.invoice_id.invoice_line: amount_advance = expense.amount if float_compare(amount_advance, advance_expense.amount_to_clearing, 2) == 1: amount_advance = advance_expense.amount_to_clearing advance_line = advance_expense.invoice_id.invoice_line[0] advance_line.copy({ 'invoice_id': invoice.id, 'price_unit': -amount_advance, 'sequence': 1, }) # If no invoice line, use advance line and change it to invoice line elif advance_expense.line_ids: advance_line = advance_expense.line_ids[0] advance_account_id = advance_line._get_non_product_account_id() line_dict = advance_line.copy_data() for line in line_dict: # Remove some key keys = [ 'expense_id', 'inrev_activity_id', 'description', 'ref' ] for key in keys: del line[key] # Change some key inv_exp = { 'quantity': 'unit_quantity', 'account_analytic_id': 'analytic_account', 'price_unit': 'unit_amount', 'invoice_line_tax_id': 'tax_ids', } for new_key, old_key in inv_exp.iteritems(): line[new_key] = line.pop(old_key) # Added fields cleared_ids = advance_expense.advance_clearing_ids max_clear_amount = advance_expense.amount_advanced - \ sum(cleared_ids.mapped('clearing_amount')) amount_advance = expense.amount if float_compare(amount_advance, max_clear_amount, 2) == 1: amount_advance = max_clear_amount line.update({ 'account_id': advance_account_id, 'invoice_id': invoice.id, 'price_unit': -amount_advance, 'sequence': 1, }) self.env['account.invoice.line'].create(line) else: raise ValidationError(_('No advance product line to reference')) return True
def testReopen(self): """Test re-opening a petty cash fund""" # Create a fund and close it # pcf1 = self.create_fund('Petty Cash Fund 01') self.assertEqual(pcf1.state, 'open') # Run the close wizard Wizard = self.env['account.pettycash.fund.close'] ctx = self.env.context.copy() ctx.update({'active_id': pcf1.id}) wiz = Wizard.sudo(self.uidFinMgr).with_context(ctx).create({ 'receivable_account': self.receivable_account.id, 'effective_date': datetime.today().date(), }) self.assertEqual(wiz.fund.id, pcf1.id) wiz.sudo(self.uidFinMgr).close_fund() self.assertEqual(pcf1.state, 'closed') self.assertFalse(pcf1.active) # Re-open the fund Wizard = self.env['account.pettycash.fund.reopen'] ctx = self.env.context.copy() ctx.update({'active_id': pcf1.id}) wiz = Wizard.sudo(self.uidFinMgr).with_context(ctx).create({ 'payable_account': self.payable_account.id, 'effective_date': datetime.today().date(), }) wiz.sudo(self.uidFinMgr).reopen_fund() self.assertEqual(pcf1.state, 'open') self.assertTrue(pcf1.active) self.assertEqual(wiz.payable_move.state, 'posted') # Check ledger accounts have been updated properly: # Accounts payable should have a credit for the fund amount. # The fund account should have a debit for same amount. move = wiz.payable_move ml1 = move.line_id[0] ml2 = move.line_id[1] self.assertEqual( float_compare(ml1.debit, wiz.fund_amount, precision_digits=2), 0) self.assertTrue(float_is_zero(ml1.credit, precision_digits=2)) self.assertEqual(ml1.account_id.id, self.account.id) self.assertEqual( float_compare(ml2.credit, wiz.fund_amount, precision_digits=2), 0) self.assertTrue(float_is_zero(ml2.debit, precision_digits=2)) self.assertEqual(ml2.account_id.id, self.payable_account.id)
def _get_invoiced(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for order in self: if order.state != 'purchase': order.invoice_status = 'no' continue if any(float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) == -1 for line in order.order_line): order.invoice_status = 'to invoice' elif all(float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) >= 0 for line in order.order_line): order.invoice_status = 'invoiced' else: order.invoice_status = 'no'
def _calc_new_qty_price(self, procurement, po_line=None, cancel=False): if not po_line: po_line = procurement.purchase_line_id qty = self.env['product.uom']._compute_qty(procurement.product_uom.id, procurement.product_qty, procurement.product_id.uom_po_id.id) if cancel: qty = -qty supplierinfo = self.env['product.supplierinfo']. \ search([('name', '=', po_line.order_id.partner_id.id), ('product_tmpl_id', '=', po_line.product_id.product_tmpl_id.id)], order='sequence, id', limit=1) # Make sure we use the minimum quantity of the partner corresponding to the PO. # This does not apply in case of dropshipping supplierinfo_min_qty = 0.0 if po_line.order_id.location_id.usage != 'customer' and supplierinfo: supplierinfo_min_qty = self.env['product.uom']. \ _compute_qty(supplierinfo.product_uom.id, supplierinfo.min_qty, po_line.product_id.uom_po_id.id) if supplierinfo_min_qty == 0.0 and not self.env.context.get('focus_on_procurements'): qty += po_line.product_qty elif self.env.context.get('cancelling_active_proc'): qty = sum([x.product_qty for x in po_line.procurement_ids if x.state != 'cancel' and x != procurement]) else: # Recompute quantity by adding existing running procurements. for proc in po_line.procurement_ids: qty += self.env['product.uom']. \ _compute_qty(proc.product_uom.id, proc.product_qty, proc.product_id.uom_po_id.id) if proc.state == 'running' else 0.0 qty = max(qty, supplierinfo_min_qty) if qty > 0.0 else 0.0 price = po_line.price_unit if supplierinfo: packaging_number = self.env['product.uom']. \ _compute_qty(supplierinfo.product_uom.id, supplierinfo.packaging_qty, po_line.product_id.uom_po_id.id) if float_compare(packaging_number, 0.0, precision_rounding=procurement.product_uom.rounding) == 0: packaging_number = 1 if float_compare(qty, 0.0, precision_rounding=procurement.product_uom.rounding) != 0: qty = max(qty, supplierinfo.min_qty) if float_compare(qty % packaging_number, 0.0, precision_rounding=procurement.product_uom.rounding) != 0: qty = (qty // packaging_number + 1) * packaging_number if qty != po_line.product_qty: pricelist = po_line.order_id.partner_id.property_product_pricelist_purchase price = pricelist.with_context(uom=procurement.product_uom.id). \ price_get(procurement.product_id.id, qty, po_line.order_id.partner_id.id)[pricelist.id] return qty, price
def interval_get_multi(self, cr, uid, date_and_hours_by_cal, resource=False, byday=True): def group(lst, key): lst.sort(key=itemgetter(key)) grouped = groupby(lst, itemgetter(key)) return dict([(k, [v for v in itr]) for k, itr in grouped]) # END group cr.execute("select calendar_id, dayofweek, hour_from, hour_to from resource_calendar_attendance order by hour_from") hour_res = cr.dictfetchall() hours_by_cal = group(hour_res, 'calendar_id') results = {} for d, hours, id in date_and_hours_by_cal: dt_from = datetime.strptime(d, '%Y-%m-%d %H:%M:%S') if not id: td = int(hours)*3 results[(d, hours, id)] = [(dt_from, dt_from + timedelta(hours=td))] continue dt_leave = self._get_leaves(cr, uid, id, resource) todo = hours result = [] maxrecur = 100 current_hour = dt_from.hour while float_compare(todo, 0, 4) and maxrecur: for (hour_from,hour_to) in [(item['hour_from'], item['hour_to']) for item in hours_by_cal[id] if item['dayofweek'] == str(dt_from.weekday())]: leave_flag = False if (hour_to>current_hour) and float_compare(todo, 0, 4): m = max(hour_from, current_hour) if (hour_to-m)>todo: hour_to = m+todo dt_check = dt_from.strftime('%Y-%m-%d') for leave in dt_leave: if dt_check == leave: dt_check = datetime.strptime(dt_check, '%Y-%m-%d') + timedelta(days=1) leave_flag = True if leave_flag: break else: d1 = datetime(dt_from.year, dt_from.month, dt_from.day) + timedelta(hours=int(math.floor(m)), minutes=int((m%1) * 60)) d2 = datetime(dt_from.year, dt_from.month, dt_from.day) + timedelta(hours=int(math.floor(hour_to)), minutes=int((hour_to%1) * 60)) result.append((d1, d2)) current_hour = hour_to todo -= (hour_to - m) dt_from += timedelta(days=1) current_hour = 0 maxrecur -= 1 results[(d, hours, id)] = result return results
def _compute_remarks(self): for rec in self: # Rolling > Released if float_compare(rec.rolling, rec.released_amount, 2) == 1: rolling = '{:,.2f}'.format(rec.rolling) diff = '{:,.2f}'.format(rec.rolling - rec.released_amount) rec.remarks = _('Rolling Amount: %s\n' 'Rolling > Released = %s') % (rolling, diff) # Rolling < Released if float_compare(rec.rolling, rec.released_amount, 2) == -1: rolling = '{:,.2f}'.format(rec.rolling) diff = '{:,.2f}'.format(rec.released_amount - rec.rolling) rec.remarks = _('Rolling Amount: %s\n' 'Rolling < Released = %s') % (rolling, diff)
def _create_link_for_product(operation_id, product_id, qty): '''method that creates the link between a given operation and move(s) of given product, for the given quantity. Returns True if it was possible to create links for the requested quantity (False if there was not enough quantity on stock moves)''' qty_to_assign = qty prod_obj = self.pool.get("product.product") product = prod_obj.browse(cr, uid, product_id) rounding = product.uom_id.rounding qtyassign_cmp = float_compare(qty_to_assign, 0.0, precision_rounding=rounding) if prod2move_ids.get(product_id): while prod2move_ids[product_id] and qtyassign_cmp > 0: qty_on_link = _create_link_for_index(operation_id, 0, product_id, qty_to_assign, quant_id=False) qty_to_assign -= qty_on_link qtyassign_cmp = float_compare(qty_to_assign, 0.0, precision_rounding=rounding) return qtyassign_cmp == 0
def testBalanceWithManyAccounts(self): """Test balance of multiple funds using one ledger account""" VoucherWizard = self.env['account.pettycash.fund.voucher'] # Create first fund and voucher # pcf1 = self.create_fund('Petty Cash Fund 01') vwiz_vals = { 'fund': pcf1.id, 'date': datetime.today().date(), 'partner': pcf1.custodian_partner.id, 'lines': [ (0, 0, { 'expense_account': self.expense_account.id, 'amount': 100.00}), ] } vwiz1 = VoucherWizard.sudo(self.uidOwner).create(vwiz_vals) vwiz1.sudo(self.uidOwner).create_voucher() # Create second fund and voucher # pcf2 = self.create_fund('Petty Cash Fund 02') vwiz2_vals = { 'fund': pcf2.id, 'date': datetime.today().date(), 'lines': [ (0, 0, { 'expense_account': self.expense_account.id, 'amount': 150.16}), ] } vwiz2 = VoucherWizard.sudo(self.uidOwner).create(vwiz2_vals) vwiz2.create_voucher() balance1 = pcf1.amount for l in vwiz1.lines: balance1 -= l.amount balance2 = pcf2.amount for l in vwiz2.lines: balance2 -= l.amount self.assertEqual( float_compare(pcf1.balance, balance1, precision_digits=2), 0) self.assertEqual( float_compare(pcf2.balance, balance2, precision_digits=2), 0)
def testIncreaseFundAmount(self): """Test increasing the fund amount""" # Create a fund pcf1 = self.create_fund('Petty Cash Fund 01') self.assertEqual(pcf1.state, 'open') # Increase the fund Wizard = self.env['account.pettycash.fund.change'] ctx = self.env.context.copy() ctx.update({'active_id': pcf1.id}) wiz = Wizard.sudo(self.uidFinMgr).with_context(ctx).create({ 'new_amount': 10000.00, 'payable_account': self.payable_account.id, 'effective_date': datetime.today().date(), 'custodian': self.uidInv.id, 'fund_name': 'Changed name', }) self.assertEqual(wiz.fund.id, pcf1.id) self.assertEqual( float_compare(wiz.fund_amount, pcf1.amount, precision_digits=2), 0) diff_amount = wiz.new_amount - wiz.fund_amount wiz.sudo(self.uidFinMgr).change_fund() self.assertEqual(pcf1.name, 'Changed name') self.assertEqual(pcf1.custodian.id, self.uidInv.id) self.assertEqual( float_compare(pcf1.amount, 10000.00, precision_digits=2), 0) self.assertEqual(wiz.move.state, 'posted') # Check ledger accounts have been updated properly: # Accounts payable should have a credit for the fund amount. # The fund account should have a debit for same amount. move = wiz.move ml1 = move.line_id[0] ml2 = move.line_id[1] self.assertEqual( float_compare(ml1.debit, diff_amount, precision_digits=2), 0) self.assertTrue(float_is_zero(ml1.credit, precision_digits=2)) self.assertEqual(ml1.account_id.id, self.account.id) self.assertEqual( float_compare(ml2.credit, diff_amount, precision_digits=2), 0) self.assertTrue(float_is_zero(ml2.debit, precision_digits=2)) self.assertEqual(ml2.account_id.id, self.payable_account.id)
def _quant_split(self, quant, qty): prec = quant.product_id.uom_id.rounding result = super(StockQuant, self)._quant_split(quant, qty) old_neg = float_compare(float_round(quant.qty, precision_rounding=prec), 0, precision_rounding=prec) <= 0 new_neg = False if result: new_neg = float_compare(float_round(result.qty, precision_rounding=prec), 0, precision_rounding=prec) <= 0 if (not config["test_enable"] or self.env.context.get('stock_forbid_negative_quants')) \ and (old_neg or new_neg) and quant.product_id.type == 'product': raise ValueError(_("Quant split: you are not allowed to create a negative or null quant. " "Product: %s, Quant qty: %s, Required reduction to: %s, Location: %s," " Lot: %s, Package: %s") % (quant.product_id.display_name, quant.qty, qty, quant.location_id.complete_name, quant.lot_id.name or '-', quant.package_id.name or '-')) return result
def recalculate_state(self, move): reserved = move.reserved_availability uom_qty = move.product_uom_qty if not reserved: move.write({'state': 'confirmed', 'partially_available': False}) elif float_compare(reserved, uom_qty, precision_rounding=0.01) == 0: move.write({'state': 'assigned', 'partially_available': False}) elif float_compare(reserved, uom_qty, precision_rounding=0.01) < 0: move.write({'state': 'confirmed', 'partially_available': True}) else: raise except_orm( _('Error'), _('reserved quantity (%s) greater than move \ quantity (%s)' % (reserved, uom_qty))) return
def test_01_action_scan_bvr(self): """ Check state of wizard passe in need information state if no partner has an adherent number equal to the one in bvr scan line 0100003949753>120000000000234478943216899+ 010001628> """ cr, uid = self.cr, self.uid bvr_string = '0100003949753>120000000000234478943216899+ 010001628>' wizard_id = self.ScanBVR.create( cr, uid, {'bvr_string': bvr_string, 'journal_id': self.purchase_journal_id, }, context={}) act_win = self.ScanBVR.validate_bvr_string( cr, uid, [wizard_id], context={}) wizard = self.ScanBVR.browse( cr, uid, wizard_id, context=None) assert wizard.state == 'need_extra_info' self.ScanBVR.write( cr, uid, wizard.id, { 'partner_id': self.partner1.id, 'bank_account_id': self.partner1bank1.id, }, context={}) act_win = self.ScanBVR.validate_bvr_string( cr, uid, [wizard_id], context={}) assert act_win['res_id'] assert self.partner1bank1.bvr_adherent_num new_invoice = self.Invoice.browse(cr, uid, act_win['res_id']) assert float_compare(new_invoice.amount_total, 3949.75, precision_rounding=0.01) == 0
def _prepare_invoice_line_from_po_line(self, line): if line.product_id.purchase_method == 'purchase': qty = line.product_qty - line.qty_invoiced else: qty = line.qty_received - line.qty_invoiced if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0: qty = 0.0 taxes = line.taxes_id invoice_line_tax_ids = self.purchase_id.fiscal_position_id.map_tax(taxes) invoice_line = self.env['account.invoice.line'] data = { 'purchase_line_id': line.id, 'name': line.name, 'origin': self.purchase_id.origin, 'uom_id': line.product_uom.id, 'product_id': line.product_id.id, 'account_id': invoice_line.with_context({'journal_id': self.journal_id.id, 'type': 'in_invoice'})._default_account(), 'price_unit': line.order_id.currency_id.compute(line.price_unit, self.currency_id, round=False), 'quantity': qty, 'discount': 0.0, 'account_analytic_id': line.account_analytic_id.id, 'invoice_line_tax_ids': invoice_line_tax_ids.ids } account = invoice_line.get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id) if account: data['account_id'] = account.id return data
def purchase_order_change(self): result = [] if not self.purchase_id: return {} if not self.partner_id: self.partner_id = self.purchase_id.partner_id.id # Keep existing lines. We want to be able to add several PO on the same invoice. for line in self.invoice_line_ids: result.append( { "purchase_line_id": line.purchase_line_id.id, "name": line.name, "origin": line.origin, "uom_id": line.uom_id.id, "product_id": line.product_id.id, "account_id": line.account_id.id, "price_unit": line.price_unit, "quantity": line.quantity, "discount": line.discount, "account_analytic_id": line.account_analytic_id.id, "invoice_line_tax_ids": line.invoice_line_tax_ids.ids, } ) for line in self.purchase_id.order_line: if line.product_id.purchase_method == "purchase": qty = line.product_qty - line.qty_invoiced else: qty = line.qty_received - line.qty_invoiced if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0: qty = 0.0 taxes = line.taxes_id or line.product_id.supplier_taxes_id invoice_line_tax_ids = self.purchase_id.fiscal_position_id.map_tax(taxes) data = { "purchase_line_id": line.id, "name": line.name, "origin": self.purchase_id.origin, "uom_id": line.product_uom.id, "product_id": line.product_id.id, "account_id": self.env["account.invoice.line"] .with_context({"journal_id": self.journal_id.id, "type": "in_invoice"}) ._default_account(), "price_unit": line.price_unit, "quantity": qty, "discount": 0.0, "account_analytic_id": line.account_analytic_id.id, "invoice_line_tax_ids": invoice_line_tax_ids.ids, } account = self.env["account.invoice.line"].get_invoice_line_account( "in_invoice", line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id ) if account: data["account_id"] = account.id result.append(data) self.invoice_line_ids = False # To avoid duplicates self.invoice_line_ids = result self.purchase_id = False return {}
def _swedish_add_invoice_line(self, cr, uid, invoice, amounts, rounded_total, delta, context=None): """ Create a invoice_line with the diff of rounding """ invoice_line_obj = self.pool.get('account.invoice.line') obj_precision = self.pool.get('decimal.precision') prec = obj_precision.precision_get(cr, uid, 'Account') company = invoice.company_id if not invoice.global_round_line_id: new_invoice_line = { 'name': _('Rounding'), 'price_unit': -delta, 'account_id': company.tax_calculation_rounding_account_id.id, 'invoice_id': invoice.id, 'is_rounding': True, } invoice_line_obj.create(cr, uid, new_invoice_line, context=context) elif float_compare(invoice.global_round_line_id.price_unit, -delta, precision_digits=prec) != 0: invoice_line_obj.write( cr, uid, invoice.global_round_line_id.id, {'price_unit': -delta}, context=context) amount_untaxed = float_round(amounts['amount_untaxed'] - delta, precision_digits=prec) return {'amount_total': rounded_total, 'amount_untaxed': amount_untaxed}
def _remita_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if tx.acquirer_reference and data.get( 'transaction_id') != tx.acquirer_reference: invalid_parameters.append( ('Transaction Id', data.get('transaction_id'), tx.acquirer_reference)) # check what is buyed #Use transaction_id to pull in more info from Remita transaction_id = data.get('transaction_id') #transaction_id = '559f55426a93a' response = urllib2.urlopen( 'https://remita.com/?v_transaction_id=%s&type=json' % (transaction_id)) myTx = json.load(response) if float_compare(float(myTx.get('total', '0.0')), tx.amount, 2) != 0: invalid_parameters.append( ('Amount', data.get('total'), '%.2f' % tx.amount)) # if data.get('BRQ_CURRENCY') != tx.currency_id.name: # invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), tx.currency_id.name)) return invalid_parameters
def _swedish_add_invoice_line(self, invoice, rounded_total, delta): """ Create a invoice_line with the diff of rounding """ invoice_line_obj = self.env['account.invoice.line'] obj_precision = self.env['decimal.precision'] prec = obj_precision.precision_get('Account') company = invoice.company_id if not invoice.global_round_line_id.id: new_invoice_line = { 'name': _('Rounding'), 'price_unit': -delta, 'account_id': company.tax_calculation_rounding_account_id.id, 'invoice_id': invoice.id, 'is_rounding': True, } invoice_line_obj.create(new_invoice_line) elif float_compare(invoice.global_round_line_id.price_unit, -delta, precision_digits=prec) != 0: invoice_line_obj.write(invoice.global_round_line_id.id, {'price_unit': -delta}) amount_untaxed = float_round(invoice.amount_untaxed - delta, precision_digits=prec) return { 'amount_total': rounded_total, 'amount_untaxed': amount_untaxed }
def _frst_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] # Compare the local amount with the amount from the PP if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) # Compare the local currency with the currency of the pp if data.get('currency') != tx.currency_id.name: invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) # Check IBAN if not data.get('frst_iban'): invalid_parameters.append(('frst_iban', data.get('frst_iban'), 'At least some value ')) # Check BIC if not data.get('frst_bic'): invalid_parameters.append(('frst_bic', data.get('frst_bic'), 'At least some Value')) info_msg = 'FRST Payment Transaction: Invalid Parameters %s' % (pprint.pformat(invalid_parameters)) _logger.info(info_msg) print '----' print info_msg print '----' return invalid_parameters
def _get_bom_delivered(self, line): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') bom_delivered = {} # There is no dependencies between purchase and mrp if 'mrp.bom' in self.env: # In the case of a kit, we need to check if all components are shipped. We use a all or # nothing policy. A product can have several BoMs, we don't know which one was used when the # delivery was created. for bom in line.product_id.product_tmpl_id.bom_ids: if bom.type != 'phantom': continue bom_delivered[bom.id] = False product_uom_qty_bom = self.env['product.uom']._compute_qty_obj(line.product_uom, line.product_qty, bom.product_uom) bom_exploded = self.env['mrp.bom']._bom_explode(bom, line.product_id, product_uom_qty_bom)[0] for bom_line in bom_exploded: qty = 0.0 for move in line.move_ids: if move.state == 'done' and move.product_id.id == bom_line.get('product_id', False): qty += self.env['product.uom']._compute_qty(move.product_uom.id, move.product_uom_qty, bom_line['product_uom']) if float_compare(qty, bom_line['product_qty'], precision_digits=precision) < 0: bom_delivered[bom.id] = False break else: bom_delivered[bom.id] = True return bom_delivered
def do_detailed_transfer(self): stock_loc_id = self.picking_id.picking_type_id.warehouse_id.lot_stock_id.id for line in self.item_ids: if line.product_id.type == 'product': if line.sourceloc_id.id not in self.env['stock.location'].search( [('id', 'child_of', stock_loc_id)])._ids: continue quant_vals = [('product_id', '=', line.product_id.id), ('lot_id', '=', line.lot_id and line.lot_id.id or False), ('location_id', '=', line.sourceloc_id.id), '|', ('reservation_id.picking_id', '=', self.picking_id.id), ('reservation_id', '=', False)] quants = self.env['stock.quant'].search(quant_vals) total_qty = sum([x['qty'] for x in quants.read(['qty'])]) total_qty_uom = self.env['product.uom']._compute_qty( line.product_id.uom_id.id, total_qty, line.product_uom_id.id) difference = float_compare( total_qty_uom, line.quantity, precision_rounding=line.product_uom_id.rounding) if difference < 0: raise exceptions.Warning( _('Quantity error'), _('Not found enought stock in %s for product %s') % (line.sourceloc_id.name, line.product_id.name)) return super(StockTransferDetails, self).do_detailed_transfer()
def check_over_request_limit(self): self.ensure_one() Request = self.env['purchase.request'] for po_line in self.order_line: subtotal_value = 0.0 list_product = [] list_request = [] request_lines = po_line.requisition_line_id.purchase_request_lines for req_line in request_lines: subtotal_value += req_line.price_subtotal if req_line.name not in list_product: list_product.append(req_line.name) if req_line.request_id.id not in list_request: list_request.append(req_line.request_id.id) ref_requests = Request.search([('request_ref_id', 'in', list_request)]) if not ref_requests: continue for ref_req in ref_requests: for ref_req_line in ref_req.line_ids: if ref_req_line.name in list_product: subtotal_value += ref_req_line.price_subtotal # When order amount > pr amount, do not allow. if float_compare(po_line.product_qty * po_line.price_unit, subtotal_value, 2) == 1: raise ValidationError( _("Some order line's price is over than request's price")) return True
def _check_balance(self, vals): """Check if move is balanced""" line_dicts = [y[2] for y in vals['line_id']] debit = sum(x.get('debit') or 0.0 for x in line_dicts) credit = sum(x.get('credit') or 0.0 for x in line_dicts) if float_compare(debit, credit, precision_digits=2): raise ValueError('Move is not balanced %s %s' % (debit, credits))
def _bpd_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) if data.get('currency') != tx.currency_id.name: invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) tx_bpd_request = {} if tx.acquirer_id.environment == 'prod': tx_bpd_request.update({ "Channel": tx.acquirer_id.bpd_channel_prod, "Store": tx.acquirer_id.bpd_store_prod, "PosInputMode": tx.acquirer_id.bpd_posinputmode_prod }) tx_url = tx.acquirer_id.bpd_url_prod Auth1 = tx.acquirer_id.bpd_auth1_prod Auth2 = tx.acquirer_id.bpd_auth2_prod else: tx_bpd_request.update({ "Channel": tx.acquirer_id.bpd_channel_test, "Store": tx.acquirer_id.bpd_store_test, "PosInputMode": tx.acquirer_id.bpd_posinputmode_test }) tx_url = tx.acquirer_id.bpd_url_test Auth1 = tx.acquirer_id.bpd_auth1_test Auth2 = tx.acquirer_id.bpd_auth2_test # cc_month, cc_year = data.get("cc_expiry").replace(" ", "").split("/") tx_bpd_request.update({ # "CardNumber": u"4012000077777777", "CardNumber": int(data.get("cc_number").replace(" ", "")), "Expiration": 201701,#int("20%s%s" % (cc_year, cc_month)), "CVC": 201,#int(data.get("cc_cvc")), "TrxType": "Sale", "Amount": 100,#'%d' % int(float_round(float(data['amount']), 2) * 100), "CurrencyPosCode": "$" if data.get("currency") == u"DOP" else u"U$S", "Payments": "1", "Plan": "0", "AcquirerRefData": "1", "CustomerServicePhone": tx.acquirer_id.service_phone, "OrderNumber": data['reference'], "ECommerceUrl": tx.acquirer_id.ecommerceurl}) request = urllib2.Request(tx_url, json.dumps(tx_bpd_request)) request.add_header('Auth1', Auth1) request.add_header('Auth2', Auth2) request.add_header('Content-type', 'application/json') request = urllib2.urlopen(request) result = request.read() print result _logger.info('=========================BPD DEBUG RESPONSE BLOCK===========================') # debug from pprint import pprint as pp _logger.info(pp(json.loads(result))) # debug _logger.info('=========================BPD DEBUG RESPONSE BLOCK===========================') # debug invalid_parameters.append(('cc_cvc', data.get('currency'), tx.currency_id.name)) return invalid_parameters
def _transfer_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if float_compare(float(data.get("amount", "0.0")), tx.amount, 2) != 0: invalid_parameters.append(("amount", data.get("amount"), "%.2f" % tx.amount)) if data.get("currency") != tx.currency_id.name: invalid_parameters.append(("currency", data.get("currency"), tx.currency_id.name)) return invalid_parameters
def _authorize_form_get_invalid_parameters(self, tx, data): invalid_parameters = [] if self.acquirer_reference and data.get("x_trans_id") != self.acquirer_reference: invalid_parameters.append(("Transaction Id", data.get("x_trans_id"), self.acquirer_reference)) # check what is buyed if float_compare(float(data.get("x_amount", "0.0")), tx.amount, 2) != 0: invalid_parameters.append(("Amount", data.get("x_amount"), "%.2f" % tx.amount)) return invalid_parameters
def _prepare_order_line_move(self, cr, uid, order, order_line, picking_id, group_id, context=None): ''' prepare the stock move data from the PO line. This function returns a list of dictionary ready to be used in stock.move's create()''' product_uom = self.pool.get('product.uom') checke_tax = order_line.checke_tax if order_line.product_uom.id != order_line.product_id.uom_id.id: checke_tax *= order_line.product_uom.factor / order_line.product_id.uom_id.factor if order.currency_id.id != order.company_id.currency_id.id: #we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency checke_tax = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, checke_tax, round=False, context=context) res = [] move_template = { 'name': order_line.name or '', 'product_id': order_line.product_id.id, 'product_uom': order_line.product_uom.id, 'product_uos': order_line.product_uom.id, 'date': order.date_order, 'date_expected': fields.date.date_to_datetime(self, cr, uid, order_line.date_planned, context), 'location_id': order.partner_id.property_stock_supplier.id, 'location_dest_id': order.location_id.id, 'picking_id': picking_id, 'partner_id': order.dest_address_id.id, 'move_dest_id': False, 'state': 'draft', 'purchase_line_id': order_line.id, 'company_id': order.company_id.id, 'checke_tax': checke_tax, 'picking_type_id': order.picking_type_id.id, 'group_id': group_id, 'procurement_id': False, 'origin': order.name, 'route_ids': order.picking_type_id.warehouse_id and [(6, 0, [x.id for x in order.picking_type_id.warehouse_id.route_ids])] or [], 'warehouse_id':order.picking_type_id.warehouse_id.id, 'invoice_state': order.invoice_method == 'picking' and '2binvoiced' or 'none', } diff_quantity = order_line.product_qty for procurement in order_line.procurement_ids: procurement_qty = product_uom._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, to_uom_id=order_line.product_uom.id) tmp = move_template.copy() tmp.update({ 'product_uom_qty': min(procurement_qty, diff_quantity), 'product_uos_qty': min(procurement_qty, diff_quantity), 'move_dest_id': procurement.move_dest_id.id, #move destination is same as procurement destination 'group_id': procurement.group_id.id or group_id, #move group is same as group of procurements if it exists, otherwise take another group 'procurement_id': procurement.id, 'invoice_state': procurement.rule_id.invoice_state or (procurement.location_id and procurement.location_id.usage == 'customer' and procurement.invoice_state=='2binvoiced' and '2binvoiced') or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale 'propagate': procurement.rule_id.propagate, }) diff_quantity -= min(procurement_qty, diff_quantity) res.append(tmp) #if the order line has a bigger quantity than the procurement it was for (manually changed or minimal quantity), then #split the future stock move in two because the route followed may be different. if float_compare(diff_quantity, 0.0, precision_rounding=order_line.product_uom.rounding) > 0: move_template['product_uom_qty'] = diff_quantity move_template['product_uos_qty'] = diff_quantity res.append(move_template) return res
def _prepare_order_line_move(self, order, order_line, picking_id, group_id): product_uom = self.env['product.uom'] price_unit = order_line.price_unit if order_line.product_uom.id != order_line.product_id.uom_id.id: price_unit *= order_line.product_uom.factor / order_line.product_id.uom_id.factor if order.currency_id.id != order.company_id.currency_id.id: #we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency price_unit = self.env['res.currency'].compute(order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False) res = [] move_template = { 'name': order_line.name or '', 'product_id': order_line.product_id.id, 'product_uom': order_line.product_uom.id, 'product_uos': order_line.product_uom.id, 'date': order.date, 'date_expected': self.date_to_datetime(self, order_line.date_planned), 'location_id': order_line.supplier_id.property_stock_supplier.id, 'location_dest_id': order.location_id.id, 'picking_id': picking_id.id, 'partner_id': order_line.supplier_id.id, 'move_dest_id': False, 'state': 'draft', 'purchase_line_id': order_line.id, 'company_id': order.company_id.id, 'price_unit': price_unit, 'picking_type_id': order.picking_type_id.id, 'group_id': group_id.id, 'procurement_id': False, 'origin': order.number, 'route_ids': order.picking_type_id.warehouse_id and [(6, 0, [x.id for x in order.picking_type_id.warehouse_id.route_ids])] or [], 'warehouse_id':order.picking_type_id.warehouse_id.id, 'invoice_state': '2binvoiced',#For moment use static. Todo Ecosoft Check. } diff_quantity = order_line.product_qty for procurement in order_line.procurement_ids: procurement_qty = product_uom._compute_qty(procurement.product_uom.id, procurement.product_qty, to_uom_id=order_line.product_uom.id) tmp = move_template.copy() tmp.update({ 'product_uom_qty': min(procurement_qty, diff_quantity), 'product_uos_qty': min(procurement_qty, diff_quantity), 'move_dest_id': procurement.move_dest_id.id, #move destination is same as procurement destination 'group_id': procurement.group_id and procurement.group_id.id or group_id and group_id.id or False, #move group is same as group of procurements if it exists, otherwise take another group 'procurement_id': procurement.id, #'invoice_state': procurement.rule_id.invoice_state or (procurement.location_id and procurement.location_id.usage == 'customer' and procurement.invoice_state=='2binvoiced' and '2binvoiced') or (order.invoice_method == 'picking' and '2binvoiced') or 'none', #dropship case takes from sale 'invoice_state': '2binvoiced', 'propagate': procurement.rule_id.propagate, }) diff_quantity -= min(procurement_qty, diff_quantity) res.append(tmp) #if the order line has a bigger quantity than the procurement it was for (manually changed or minimal quantity), then #split the future stock move in two because the route followed may be different. if float_compare(diff_quantity, 0.0, precision_rounding=order_line.product_uom.rounding) > 0: move_template['product_uom_qty'] = diff_quantity move_template['product_uos_qty'] = diff_quantity res.append(move_template) return res
def purchase_order_change(self): result = [] if not self.purchase_id: return {} if not self.partner_id: self.partner_id = self.purchase_id.partner_id.id # Keep existing lines. We want to be able to add several PO on the same invoice. for line in self.invoice_line_ids: result.append({ 'purchase_line_id': line.purchase_line_id.id, 'name': line.name, 'origin': line.origin, 'uom_id': line.uom_id.id, 'product_id': line.product_id.id, 'account_id': line.account_id.id, 'price_unit': line.price_unit, 'quantity': line.quantity, 'discount': line.discount, 'account_analytic_id': line.account_analytic_id.id, 'invoice_line_tax_ids': line.invoice_line_tax_ids.ids, }) for line in self.purchase_id.order_line: # Load a PO line only once if line in self.invoice_line_ids.mapped('purchase_line_id'): continue if line.product_id.purchase_method == 'purchase': qty = line.product_qty - line.qty_invoiced else: qty = line.qty_received - line.qty_invoiced if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0: qty = 0.0 taxes = line.taxes_id or line.product_id.supplier_taxes_id invoice_line_tax_ids = self.purchase_id.fiscal_position_id.map_tax(taxes) data = { 'purchase_line_id': line.id, 'name': line.name, 'origin': self.purchase_id.origin, 'uom_id': line.product_uom.id, 'product_id': line.product_id.id, 'account_id': self.env['account.invoice.line'].with_context({'journal_id': self.journal_id.id, 'type': 'in_invoice'})._default_account(), 'price_unit': line.order_id.currency_id.compute(line.price_unit, self.currency_id), 'quantity': qty, 'discount': 0.0, 'account_analytic_id': line.account_analytic_id.id, 'invoice_line_tax_ids': invoice_line_tax_ids.ids } account = self.env['account.invoice.line'].get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id) if account: data['account_id'] = account.id result.append(data) self.invoice_line_ids = False # To avoid duplicates self.invoice_line_ids = result self.purchase_id = False return {}
def _invoice_form_get_invalid_parameters(self, tx, data): invalid_parameters = [] if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) if data.get('currency') != tx.currency_id.name: invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) return invalid_parameters
def _authorize_form_get_invalid_parameters(self, tx, data): invalid_parameters = [] if self.acquirer_reference and data.get('x_trans_id') != self.acquirer_reference: invalid_parameters.append(('Transaction Id', data.get('x_trans_id'), self.acquirer_reference)) # check what is buyed if float_compare(float(data.get('x_amount', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('Amount', data.get('x_amount'), '%.2f' % tx.amount)) return invalid_parameters
def _savedcc_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) if data.get('currency') != tx.currency_id.name: invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) return invalid_parameters
def onchange_enddate(self, cr, uid, ids, employee_id, date_from, date_to, holiday_status_id, no_days, context=None): ee_obj = self.pool.get('hr.employee') holiday_obj = self.pool.get('hr.holidays.public') sched_tpl_obj = self.pool.get('hr.schedule.template') res = {'value': {'return_date': False}} if not employee_id or not date_to or (float_compare(no_days, 0.0, precision_rounding=0.01) == -1): return res if holiday_status_id: hs_data = self.pool.get('hr.holidays.status').read(cr, uid, holiday_status_id, ['ex_rest_days', 'ex_public_holidays'], context=context) else: hs_data = {} ex_rd = hs_data.get('ex_rest_days', False) ex_ph = hs_data.get('ex_public_holidays', False) rest_days = [] if ex_rd: ee = ee_obj.browse(cr, uid, employee_id, context=context) if ee.contract_id and ee.contract_id.schedule_template_id: rest_days = sched_tpl_obj.get_rest_days(cr, uid, ee.contract_id.schedule_template_id.id, context=context) dt = datetime.strptime(date_to, OE_DTFORMAT) return_date = dt + timedelta(days= +1) while (return_date.weekday() in rest_days and ex_rd) or (holiday_obj.is_public_holiday(cr, uid, return_date.date(), context=context) and ex_ph): return_date += timedelta(days=1) res['value']['return_date'] = return_date.strftime('%B %d, %Y') # If the number of requested days is zero it means this is a partial day request. # Assume that a full day of work is 8 hours. # if float_compare(no_days, 1.0, precision_rounding=0.01) == -1: dtStart = datetime.strptime(date_from, OE_DTFORMAT) delta = dt - dtStart res['value'].update({'number_of_days_temp': float(delta.seconds) / (8.0 * 60.0 * 60.0)}) res['value']['return_date'] = False return res
def _get_invoiced(self): precision = self.env["decimal.precision"].precision_get("Product Unit of Measure") for order in self: if order.state != "purchase": order.invoice_status = "no" continue if any( float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) == -1 for line in order.order_line ): order.invoice_status = "to invoice" elif all( float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) >= 0 for line in order.order_line ): order.invoice_status = "invoiced" else: order.invoice_status = "no"
def _santander_form_get_invalid_parameters(self, tx, data): print "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" invalid_parameters = [] if (tx.acquirer_reference and data.get("ORDER_ID")) != tx.acquirer_reference: invalid_parameters.append(("Transaction Id", data.get("ORDER_ID"), tx.acquirer_reference)) # check what is buyed if float_compare(float(data.get("AMOUNT", "0.0")) / 100, tx.amount, 2) != 0: invalid_parameters.append(("Amount", data.get("AMOUNT"), "%.2f" % tx.amount)) return invalid_parameters
def _alipay_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): invalid_parameters = [] if tx.acquirer_reference and data.get('out_trade_no') != tx.acquirer_reference: invalid_parameters.append(('Transaction Id', data.get('out_trade_no'), tx.acquirer_reference)) if float_compare(float(data.get('total_fee', '0.0')), tx.amount, 2) != 0: invalid_parameters.append(('Amount', data.get('total_fee'), '%.2f' % tx.amount)) return invalid_parameters
def _create_stock_moves(self, picking): moves = self.env['stock.move'] done = self.env['stock.move'].browse() for line in self: order = line.order_id price_unit = line.price_unit if line.taxes_id: price_unit = line.taxes_id.compute_all(price_unit, currency=line.order_id.currency_id, quantity=1.0)['total_excluded'] if line.product_uom.id != line.product_id.uom_id.id: price_unit *= line.product_uom.factor / line.product_id.uom_id.factor if order.currency_id != order.company_id.currency_id: price_unit = order.currency_id.compute(price_unit, order.company_id.currency_id, round=False) template = { 'name': line.name or '', 'product_id': line.product_id.id, 'product_uom': line.product_uom.id, 'date': line.order_id.date_order, 'date_expected': line.date_planned, 'location_id': line.order_id.partner_id.property_stock_supplier.id, 'location_dest_id': line.order_id._get_destination_location(), 'picking_id': picking.id, 'partner_id': line.order_id.dest_address_id.id, 'move_dest_id': False, 'state': 'draft', 'purchase_line_id': line.id, 'company_id': line.order_id.company_id.id, 'price_unit': price_unit, 'picking_type_id': line.order_id.picking_type_id.id, 'group_id': line.order_id.group_id.id, 'procurement_id': False, 'origin': line.order_id.name, 'route_ids': line.order_id.picking_type_id.warehouse_id and [(6, 0, [x.id for x in line.order_id.picking_type_id.warehouse_id.route_ids])] or [], 'warehouse_id':line.order_id.picking_type_id.warehouse_id.id, } # Fullfill all related procurements with this po line diff_quantity = line.product_qty for procurement in line.procurement_ids: procurement_qty = procurement.product_uom._compute_qty_obj(procurement.product_uom, procurement.product_qty, line.product_uom) tmp = template.copy() tmp.update({ 'product_uom_qty': min(procurement_qty, diff_quantity), 'move_dest_id': procurement.move_dest_id.id, #move destination is same as procurement destination 'procurement_id': procurement.id, 'propagate': procurement.rule_id.propagate, }) done += moves.create(tmp) diff_quantity -= min(procurement_qty, diff_quantity) if float_compare(diff_quantity, 0.0, precision_rounding=line.product_uom.rounding) > 0: template['product_uom_qty'] = diff_quantity done += moves.create(template) return done