Пример #1
0
 def _make_calculations_for_create_procurement(
         self, cr, uid, prods, op, use_new_cursor, context=None):
     procurement_obj = self.pool['procurement.order']
     orderpoint_obj = self.pool['stock.warehouse.orderpoint']
     result = float_compare(prods, op.product_min_qty,
                            precision_rounding=op.product_uom.rounding)
     if result < 0:
         qty = (max(op.product_min_qty, op.product_max_qty) - prods)
         reste = (op.qty_multiple > 0 and qty % op.qty_multiple or 0.0)
         result = float_compare(reste, 0.0,
                                precision_rounding=op.product_uom.rounding)
         if result > 0:
             qty += op.qty_multiple - reste
         result = float_compare(qty, 0.0,
                                precision_rounding=op.product_uom.rounding)
         if result > 0:
             qty -= orderpoint_obj.subtract_procurements(
                 cr, uid, op, context=context)
             qty_rounded = float_round(
                 qty, precision_rounding=op.product_uom.rounding)
             if qty_rounded > 0:
                 vals = self._prepare_orderpoint_procurement(
                     cr, uid, op, qty_rounded, context=context)
                 proc_id = procurement_obj.create(
                     cr, uid, vals, context=context)
                 self.check(cr, uid, [proc_id])
                 self.run(cr, uid, [proc_id])
     if use_new_cursor:
         cr.commit()
Пример #2
0
 def test_coda_file_import(self):
     cr, uid = self.cr, self.uid
     self.statement_import_model.import_file(cr, uid, [self.bank_statement_id], context=self.context)
     statement_id = self.bank_statement_model.search(cr, uid, [("name", "=", "135")])[0]
     bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id)
     self.assertEqual(float_compare(bank_st_record.balance_start, 11812.70, precision_digits=2), 0)
     self.assertEqual(float_compare(bank_st_record.balance_end_real, 13646.05, precision_digits=2), 0)
Пример #3
0
 def _compute_invoice_status(self):
     """
     Compute the invoice status of a SO line. Possible statuses:
     - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to
       invoice. This is also hte default value if the conditions of no other status is met.
     - to invoice: we refer to the quantity to invoice of the line. Refer to method
       `_get_to_invoice_qty()` for more information on how this quantity is calculated.
     - upselling: this is possible only for a product invoiced on ordered quantities for which
       we delivered more than expected. The could arise if, for example, a project took more
       time than expected but we decided not to invoice the extra cost to the client. This
       occurs onyl in state 'sale', so that when a SO is set to done, the upselling opportunity
       is removed from the list.
     - invoiced: the quantity invoiced is larger or equal to the quantity ordered.
     """
     precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
     for line in self:
         if line.state not in ('sale', 'done'):
             line.invoice_status = 'no'
         elif not float_is_zero(line.qty_to_invoice, precision_digits=precision):
             line.invoice_status = 'to invoice'
         elif line.state == 'sale' and line.product_id.invoice_policy == 'order' and\
                 float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) == 1:
             line.invoice_status = 'upselling'
         elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) >= 0:
             line.invoice_status = 'invoiced'
         else:
             line.invoice_status = 'no'
Пример #4
0
    def _quant_create(self, cr, uid, qty, move, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, force_location_from=False, force_location_to=False, context=None):
        quant_obj = self.pool.get('stock.quant')
        quant = super(stock_quant, self)._quant_create(cr, uid, qty, move, lot_id=lot_id, owner_id=owner_id, src_package_id=src_package_id, dest_package_id=dest_package_id, force_location_from=force_location_from, force_location_to=force_location_to, context=context)
        if move.product_id.valuation == 'real_time':
            self._account_entry_move(cr, uid, [quant], move, context)

            # If the precision required for the variable quant cost is larger than the accounting
            # precision, inconsistencies between the stock valuation and the accounting entries
            # may arise.
            # For example, a box of 13 units is bought 15.00. If the products leave the
            # stock one unit at a time, the amount related to the cost will correspond to
            # round(15/13, 2)*13 = 14.95. To avoid this case, we split the quant in 12 + 1, then
            # record the difference on the new quant.
            # We need to make sure to able to extract at least one unit of the product. There is
            # an arbitrary minimum quantity set to 2.0 from which we consider we can extract a
            # unit and adapt the cost.
            curr_rounding = move.company_id.currency_id.rounding
            cost_rounded = float_round(quant.cost, precision_rounding=curr_rounding)
            cost_correct = cost_rounded
            if float_compare(quant.product_id.uom_id.rounding, 1.0, precision_digits=1) == 0\
                    and float_compare(quant.qty * quant.cost, quant.qty * cost_rounded, precision_rounding=curr_rounding) != 0\
                    and float_compare(quant.qty, 2.0, precision_rounding=quant.product_id.uom_id.rounding) >= 0:
                qty = quant.qty
                cost = quant.cost
                quant_correct = quant_obj._quant_split(cr, uid, quant, quant.qty - 1.0, context=context)
                cost_correct += (qty * cost) - (qty * cost_rounded)
                quant_obj.write(cr, SUPERUSER_ID, [quant.id], {'cost': cost_rounded}, context=context)
                quant_obj.write(cr, SUPERUSER_ID, [quant_correct.id], {'cost': cost_correct}, context=context)
        return quant
Пример #5
0
    def _quants_get_order_all_locations(self, product, quantity, domain=[], orderby='in_date'):
        domain += [('product_id', '=', product.id)]
        if self.env.context.get('force_company'):
            domain += [('company_id', '=', self.env.context.get('force_company'))]
        else:
            domain += [('company_id', '=', self.env.user.company_id.id)]
        res = []
        offset = 0
        while float_compare(quantity, 0, precision_rounding=product.uom_id.rounding) > 0:
            quants = self.search(domain, order=orderby, limit=10, offset=offset)
            # for quant in quants:
            #     location_id = quant.location_id.id
            #     if location_id not in _location_usable_cache:
            #         _location_usable_cache[location_id] = product.with_context(
            #             location=location_id
            #         ).qty_usable

            if not quants:
                res.append((None, quantity))
                break
            for quant in quants:
                rounding = product.uom_id.rounding
                apply_qty = quant.qty
                if float_compare(value1=apply_qty, value2=0, precision_rounding=rounding) <= 0:
                    continue
                res += [(quant, apply_qty)]
                quantity -= apply_qty
                if float_is_zero(quantity, precision_rounding=rounding):
                    break

            offset += 10
        return res
Пример #6
0
 def _prepare_picking(self, receive):
     move_obj = self.env['stock.move']
     move_ids = []
     for line in receive.line_ids:
         qty = line.product_qty
         domain = [('product_id', '=', line.product_id.id), ('receive_line_id', '=', False), ('state', 'not in', ('done', 'cancel'))]
         if line.purchase_order_id:
             domain += [('purchase_line_id.order_id', '=', line.purchase_order_id.id)]
         else:
             domain += [('purchase_line_id.order_id.partner_id', '=', line.receive_id.partner_id.id)]
         for move in move_obj.search(domain):
             if tools.float_compare(qty, 0.0, precision_rounding=move.product_uom.rounding) <= 0:
                 break
             if tools.float_compare(qty, move.product_uom_qty, precision_rounding=move.product_uom.rounding) < 0:
                 move = move_obj.browse(move_obj.split(move, qty))
             move.write({'picking_type_id': receive.picking_type_id.id, 'receive_line_id': line.id})
             move_ids.append((4, move.id))
             qty -= move.product_uom_qty
         if tools.float_compare(qty, 0.0, precision_rounding=line.product_uom_id.rounding) > 0:
             raise Warning(_(u'%s 订单数量不足,多出订单数量:%s') % (line.name, qty))
     pick_vals = {
         'picking_type_id': receive.picking_type_id.id,
         'partner_id': receive.partner_id.id,
         'date': receive.date_receive,
         'move_lines': move_ids,
         'origin': receive.name,
     }
     return pick_vals
Пример #7
0
    def button_validate(self, cr, uid, ids, context=None):
        quant_obj = self.pool.get('stock.quant')

        for cost in self.browse(cr, uid, ids, context=context):
            if cost.state != 'draft':
                raise UserError(_('Only draft landed costs can be validated'))
            if not cost.valuation_adjustment_lines or not self._check_sum(cr, uid, cost, context=context):
                raise UserError(_('You cannot validate a landed cost which has no valid valuation adjustments lines. Did you click on Compute?'))
            move_id = self._create_account_move(cr, uid, cost, context=context)
            for line in cost.valuation_adjustment_lines:
                if not line.move_id:
                    continue
                per_unit = line.final_cost / line.quantity
                diff = per_unit - line.former_cost_per_unit

                # If the precision required for the variable diff is larger than the accounting
                # precision, inconsistencies between the stock valuation and the accounting entries
                # may arise.
                # For example, a landed cost of 15 divided in 13 units. If the products leave the
                # stock one unit at a time, the amount related to the landed cost will correspond to
                # round(15/13, 2)*13 = 14.95. To avoid this case, we split the quant in 12 + 1, then
                # record the difference on the new quant.
                # We need to make sure to able to extract at least one unit of the product. There is
                # an arbitrary minimum quantity set to 2.0 from which we consider we can extract a
                # unit and adapt the cost.
                curr_rounding = line.move_id.company_id.currency_id.rounding
                diff_rounded = float_round(diff, precision_rounding=curr_rounding)
                diff_correct = diff_rounded
                quants = line.move_id.quant_ids.sorted(key=lambda r: r.qty, reverse=True)
                quant_correct = False
                if quants\
                        and float_compare(quants[0].product_id.uom_id.rounding, 1.0, precision_digits=1) == 0\
                        and float_compare(line.quantity * diff, line.quantity * diff_rounded, precision_rounding=curr_rounding) != 0\
                        and float_compare(quants[0].qty, 2.0, precision_rounding=quants[0].product_id.uom_id.rounding) >= 0:
                    # Search for existing quant of quantity = 1.0 to avoid creating a new one
                    quant_correct = quants.filtered(lambda r: float_compare(r.qty, 1.0, precision_rounding=quants[0].product_id.uom_id.rounding) == 0)
                    if not quant_correct:
                        quant_correct = quants[0]._quant_split(quants[0].qty - 1.0)
                    else:
                        quant_correct = quant_correct[0]
                        quants = quants - quant_correct
                    diff_correct += (line.quantity * diff) - (line.quantity * diff_rounded)
                    diff = diff_rounded

                quant_dict = {}
                for quant in quants:
                    quant_dict[quant.id] = quant.cost + diff
                if quant_correct:
                    quant_dict[quant_correct.id] = quant_correct.cost + diff_correct
                for key, value in quant_dict.items():
                    quant_obj.write(cr, SUPERUSER_ID, key, {'cost': value}, context=context)
                qty_out = 0
                for quant in line.move_id.quant_ids:
                    if quant.location_id.usage != 'internal':
                        qty_out += quant.qty
                self._create_accounting_entries(cr, uid, line, move_id, qty_out, context=context)
            self.write(cr, uid, cost.id, {'state': 'done', 'account_move_id': move_id}, context=context)
            self.pool.get('account.move').post(cr, uid, [move_id], context=context)
        return True
Пример #8
0
 def _check_holidays(self):
     for holiday in self:
         if holiday.holiday_type != 'employee' or holiday.type != 'remove' or not holiday.employee_id or holiday.holiday_status_id.limit:
             continue
         leave_days = holiday.holiday_status_id.get_days(holiday.employee_id.id)[holiday.holiday_status_id.id]
         if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \
           float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
             raise ValidationError(_('The number of remaining leaves is not sufficient for this leave type.\n'
                                     'Please verify also the leaves waiting for validation.'))
Пример #9
0
def machin(cr, uid, ids, context=None):

# Conversion de devises
self.with_context(date=date).from_currency.compute(amount_to_convert, to_currency_obj, round=True)

# FLOAT
float_compare(value1, value2, precision_digits=None, precision_rounding=None)

returns -1, 0 or 1, if ``value1`` is lower than,
           equal to, or greater than ``value2``, at the given precision.
Пример #10
0
    def create_move(self, post_move=True):
        created_moves = self.env['account.move']
        for line in self:
            depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
            company_currency = line.asset_id.company_id.currency_id
            current_currency = line.asset_id.currency_id
            amount = current_currency.compute(line.amount, company_currency)
            sign = (line.asset_id.category_id.journal_id.type == 'purchase' or line.asset_id.category_id.journal_id.type == 'sale' and 1) or -1
            asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
            reference = line.asset_id.code
            journal_id = line.asset_id.category_id.journal_id.id
            partner_id = line.asset_id.partner_id.id
            categ_type = line.asset_id.category_id.type
            debit_account = line.asset_id.category_id.account_asset_id.id
            credit_account = line.asset_id.category_id.account_depreciation_id.id
            prec = self.env['decimal.precision'].precision_get('Account')
            move_line_1 = {
                'name': asset_name,
                'account_id': credit_account,
                'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
                'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
                'journal_id': journal_id,
                'partner_id': partner_id,
                'currency_id': company_currency != current_currency and current_currency.id or False,
                'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
                'analytic_account_id': line.asset_id.category_id.account_analytic_id.id if categ_type == 'sale' else False,
                'date': depreciation_date,
            }
            move_line_2 = {
                'name': asset_name,
                'account_id': debit_account,
                'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
                'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
                'journal_id': journal_id,
                'partner_id': partner_id,
                'currency_id': company_currency != current_currency and current_currency.id or False,
                'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
                'analytic_account_id': line.asset_id.category_id.account_analytic_id.id if categ_type == 'purchase' else False,
                'date': depreciation_date,
            }
            move_vals = {
                'ref': reference,
                'date': depreciation_date or False,
                'journal_id': line.asset_id.category_id.journal_id.id,
                'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
                'asset_id': line.asset_id.id,
                }
            move = self.env['account.move'].create(move_vals)
            line.write({'move_id': move.id, 'move_check': True})
            created_moves |= move

        if post_move and created_moves:
            created_moves.filtered(lambda r: r.asset_id and r.asset_id.category_id and r.asset_id.category_id.open_asset).post()
        return [x.id for x in created_moves]
Пример #11
0
    def test_iva_16_currency_supplier_almost_complete(self):
        """
            Tests Supplier with currency USD and tax 16% and two payments
            First payment almost complete and exchange rate
                greater then invoice
            Second payment with exchange rate same that invoice
        """
        cr, uid = self.cr, self.uid
        precision = self.precision_obj.precision_get(cr, uid, 'Account')
        invoice_id = self.create_invoice_supplier(
            cr, uid, 116, [self.tax_16],
            time.strftime('%Y') + '-06-30', self.currency_usd_id)

        # validate invoice
        self.registry('account.invoice').signal_workflow(
            cr, uid, [invoice_id], 'invoice_open')
        invoice_record = self.account_invoice_model.browse(
            cr, uid, [invoice_id])

        # we search aml with account payable
        for line_invoice in invoice_record.move_id.line_id:
            if line_invoice.account_id.id == self.account_payable_id:
                line_id = line_invoice
                break

        # create payment almost complete

        move_line_ids_complete = self.create_statement(
            cr, uid, line_id, self.partner_agrolait_id, -115,
            self.bank_journal_usd_id, time.strftime('%Y') + '-06-01')
        for move_line in move_line_ids_complete:
            if move_line.account_id.id == self.acc_tax_16_payment:
                self.assertEquals(float_compare(
                    move_line.amount_base, 77.25,
                    precision_digits=precision), 0)
                self.assertNotEqual(move_line.tax_id_secondary, False)
                continue

        # create payment complete

        move_line_ids_complete = self.create_statement(
            cr, uid, line_id, self.partner_agrolait_id, -1,
            self.bank_journal_usd_id, time.strftime('%Y') + '-06-30')

        checked_line = 0
        for move_line_complete in move_line_ids_complete:
            if move_line_complete.account_id.id == self.acc_tax_16_payment:
                self.assertEquals(float_compare(
                    move_line_complete.amount_base, 0.56,
                    precision_digits=precision), 0)
                self.assertNotEqual(move_line_complete.tax_id_secondary, False)
                checked_line += 1
                continue
        self.assertEquals(checked_line, 1)
Пример #12
0
    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 = {}
        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','shipping_process'):
                            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=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=context)
                    if picking.picking_type_id.code == 'incoming':
                        self.send_mail_memco_department(cr,uid,todo_move_ids)
                elif context.get('do_only_split'):
                    context = dict(context, split=todo_move_ids)
            self._create_backorder(cr, uid, picking, context=context)
            if toassign_move_ids:
                stock_move_obj.action_assign(cr, uid, toassign_move_ids, context=context)
        return True
Пример #13
0
 def _create_link_for_product(operation_id, product_id, qty, move_id):
     '''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(move_id):
         while prod2move_ids[move_id] and qtyassign_cmp > 0:
             qty_on_link = _create_link_for_index(operation_id, 0, product_id, qty_to_assign, move_id, 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
Пример #14
0
 def _is_available(self):
     self.is_available = 'true'
     if self.order_id.state not in ['draft', 'sent']:
         return
     elif not self._check_routing(self.product_id, self.order_id.warehouse_id.id):
         if float_compare(self.product_id.virtual_available, self.product_uom_qty, precision_rounding=self.product_id.uom_id and self.product_id.uom_id.rounding or 0.01) == -1:
             self.is_available = 'false'
     elif self.order_id.purchase_ids:
         pline = None
         for p in self.order_id.purchase_ids:
             for l in p.order_line:
                 if l.product_id.id == self.product_id.id:
                     pline = l
         if pline and float_compare(pline.product_qty, self.product_uom_qty, precision_rounding=self.product_id.uom_id and self.product_id.uom_id.rounding or 0.01) == -1:
             self.is_available = 'false'
Пример #15
0
 def _compute_invoice_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.invoice_status = 'no'
         elif not float_is_zero(line.qty_to_invoice, precision_digits=precision):
             line.invoice_status = 'to invoice'
         elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) == 1 or\
                 float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) >= 0 and\
                 float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) == 1:
             line.invoice_status = 'upselling'
         elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) == 0:
             line.invoice_status = 'invoiced'
         else:
             line.invoice_status = 'no'
Пример #16
0
 def recreer_mouvements(self):
     """
     Recréer les mouvements de stocks si nomenclature OF modifiée
     """
     for obj in self:
         qt_reste=obj.is_qt_reste_uom
         for move in obj.move_created_ids:
             move.product_uom_qty=qt_reste
         cr, uid, context = self.env.args
         for move in obj.move_lines:
             move.action_cancel()
         stock_moves = []
         for line in obj.product_lines:
             if line.product_id.type != 'service':
                 qty=qt_reste*line.is_bom_qty
                 #Si la quantité restante est à 0 , mettre 0.00001 pour ne pas solder le mouvement
                 if float_compare(qty, 0, precision_rounding=line.product_uom.rounding) == 0:
                     qty=line.product_uom.rounding
                 line.product_qty=qty
                 stock_move_id = obj._make_production_consume_line(line)
                 stock_moves.append(stock_move_id)
             line.product_qty=obj.product_qty*line.is_bom_qty
         if stock_moves:
             move_obj=self.pool.get('stock.move')
             move_obj.action_confirm(cr, uid, stock_moves, context=context)
             move_obj.force_assign(cr, uid, stock_moves)
         #** Mise à jour des ordres de travaux sans supprimer les lignes ****
         res = self._prepare_lines(obj)
         results = res[1] # workcenter_lines
         for row in results:
             for line in obj.workcenter_lines:
                 if row['sequence']==line.sequence:
                     line.cycle = row['cycle']
                     line.hour  = row['hour']
Пример #17
0
 def _onchange_product_id_check_availability(self):
     if not self.product_id:
         self.product_packaging = False
         return {}
     precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
     self.product_tmpl_id = self.product_id.product_tmpl_id
     if self.product_id.type == 'product':
         product = self.product_id.with_context(
             lang=self.order_id.partner_id.lang,
             partner_id=self.order_id.partner_id.id,
             date_order=self.order_id.date_order,
             pricelist_id=self.order_id.pricelist_id.id,
             uom=self.product_uom.id,
             warehouse_id=self.order_id.warehouse_id.id
         )
         if float_compare(product.virtual_available, self.product_uom_qty, precision_digits=precision) == -1:
             # Check if MTO, Cross-Dock or Drop-Shipping
             is_available = False
             for route in self.route_id+self.product_id.route_ids:
                 for pull in route.pull_ids:
                     if pull.location_id.id == self.order_id.warehouse_id.lot_stock_id.id:
                         is_available = True
             if not is_available:
                 warning_mess = {
                     'title': _('Not enough inventory!'),
                     'message' : _('You plan to sell %.2f %s but you only have %.2f %s available!\nThe stock on hand is %.2f %s.') % \
                         (self.product_uom_qty, self.product_uom.name or self.product_id.uom_id.name, product.virtual_available, self.product_uom.name or self.product_id.uom_id.name, product.qty_available, self.product_uom.name or self.product_id.uom_id.name)
                 }
                 return {'warning': warning_mess}
     return {}
Пример #18
0
    def _action_procurement_create(self):
        """
        Create procurements based on quantity ordered. If the quantity is increased, new
        procurements are created. If the quantity is decreased, no automated action is taken.
        """
        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
        new_procs = self.env['procurement.order'] #Empty recordset
        for line in self:
            if line.state != 'sale':
                continue
            qty = 0.0
            for proc in line.procurement_ids:
                qty += proc.product_qty
            if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0:
                return False

            if not line.order_id.procurement_group_id:
                vals = line.order_id._prepare_procurement_group()
                line.order_id.procurement_group_id = self.env["procurement.group"].create(vals)

            vals = line._prepare_order_line_procurement(group_id=line.order_id.procurement_group_id.id)
            vals['product_qty'] = line.product_uom_qty - qty
            new_proc = self.env["procurement.order"].create(vals)
            new_procs += new_proc
        new_procs.run()
        return new_procs
Пример #19
0
    def _get_delivered_qty(self):
        self.ensure_one()
        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')

        # 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.
        bom_delivered = {}
        bom = self.env['mrp.bom']._bom_find(product=self.product_id)
        if bom and bom.type == 'phantom':
            bom_delivered[bom.id] = False
            product_uom_qty_bom = self.product_uom._compute_quantity(self.product_uom_qty, bom.product_uom_id)
            boms, lines = bom.explode(self.product_id, product_uom_qty_bom)
            for bom_line, data in lines:
                qty = 0.0
                for move in self.procurement_ids.mapped('move_ids'):
                    if move.state == 'done' and move.product_id.id == bom_line.product_id.id:
                        qty += move.product_uom._compute_quantity(move.product_uom_qty, bom_line.product_uom_id)
                if float_compare(qty, data['qty'], precision_digits=precision) < 0:
                    bom_delivered[bom.id] = False
                    break
                else:
                    bom_delivered[bom.id] = True
        if bom_delivered and any(bom_delivered.values()):
            return self.product_uom_qty
        elif bom_delivered:
            return 0.0
        return super(SaleOrderLine, self)._get_delivered_qty()
Пример #20
0
 def check_product_availability(self, cr, uid, product, qty=0, uom=False, context=None):
     product_uom_obj = self.pool.get('product.uom')
     product_obj = self.pool.get('product.product')
     
     uom2 = False
     if uom:
         uom2 = product_uom_obj.browse(cr, uid, uom, context=context)
         if product.uom_id.category_id.id != uom2.category_id.id or context.get('force_product_uom'):
             uom = False
             uom2 = False
     
     if not uom2:
         uom2 = product.uom_id
     compare_qty = float_compare(product.virtual_available * uom2.factor, qty * product.uom_id.factor, precision_rounding=product.uom_id.rounding)
     
     warning_msgs = ''
     
     if (product.type == 'product') and int(compare_qty) == -1  and (product.procure_method == 'make_to_stock'):
         warn_msg = _('You plan to sell %.2f %s of %s but you only have %.2f %s available !\nThe real stock of %s is %.2f %s. (without reservations)') % \
                 (qty, uom2 and uom2.name or product.uom_id.name,
                  product.name,
                  max(0,product.virtual_available), product.uom_id.name,
                  product.name,
                  max(0,product.qty_available), product.uom_id.name)
         warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"
     
     return warning_msgs
Пример #21
0
 def compute_full_after_batch_reconcile(self):
     super(AccountMoveLine, self).compute_full_after_batch_reconcile()
     #check if the reconcilation is full
     partial_rec_set = self.env['account.partial.reconcile']
     total_debit = 0
     total_credit = 0
     total_amount_currency = 0
     currency = False
     for aml in self:
         total_debit += aml.debit
         total_credit += aml.credit
         if not currency and aml.currency_id:
             currency = aml.currency_id
         if aml.currency_id and aml.currency_id == currency:
             total_amount_currency += aml.amount_currency
             partial_rec_set |= aml.matched_debit_ids | aml.matched_credit_ids
     partial_rec_ids = [x.id for x in list(partial_rec_set)]
     #if the total debit and credit are equal, and the total amount in currency is 0, the reconciliation is full
     digits_rounding_precision = self[0].company_id.currency_id.rounding
     if float_compare(total_debit, total_credit, precision_rounding=digits_rounding_precision) == 0 \
       and (not currency or float_is_zero(total_amount_currency, precision_rounding=currency.rounding)):
         #in that case, mark the reference on the partial reconciliations and the entries
         self.env['account.full.reconcile'].with_context(check_move_validity=False).create({
             'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
             'reconciled_line_ids': [(6, 0, self.ids)]})
Пример #22
0
 def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False):
     res = super(AccountMoveLine, self).reconcile(writeoff_acc_id=writeoff_acc_id, writeoff_journal_id=writeoff_journal_id)
     account_move_ids = [l.move_id.id for l in self if float_compare(l.move_id.matched_percentage, 1, precision_digits=5) == 0]
     if account_move_ids:
         expenses = self.env['hr.expense'].search([('account_move_id', 'in', account_move_ids)])
         expenses.paid_expenses()
     return res
Пример #23
0
    def form_feedback(self, cr, uid, data, acquirer_name, context=None):
        """ Override to confirm the sale order, if defined, and if the transaction
        is done. """
        tx = None
        res = super(PaymentTransaction, self).form_feedback(cr, uid, data, acquirer_name, context=context)

        # fetch the tx, check its state, confirm the potential SO
        try:
            tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
            if hasattr(self, tx_find_method_name):
                tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context)
            _logger.info('<%s> transaction processed: tx ref:%s, tx amount: %s', acquirer_name, tx.reference if tx else 'n/a', tx.amount if tx else 'n/a')

            if tx and tx.sale_order_id:
                # verify SO/TX match, excluding tx.fees which are currently not included in SO
                amount_matches = (tx.sale_order_id.state in ['draft', 'sent'] and float_compare(tx.amount, tx.sale_order_id.amount_total, 2) == 0)
                if amount_matches:
                    if tx.state == 'done':
                        _logger.info('<%s> transaction completed, confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
                        self.pool['sale.order'].action_button_confirm(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=dict(context, send_email=True))
                    elif tx.state != 'cancel' and tx.sale_order_id.state == 'draft':
                        _logger.info('<%s> transaction pending, sending quote email for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
                        self.pool['sale.order'].force_quotation_send(cr, SUPERUSER_ID, [tx.sale_order_id.id], context=context)
                else:
                    _logger.warning('<%s> transaction MISMATCH for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
        except Exception:
            _logger.exception('Fail to confirm the order or send the confirmation email%s', tx and ' for the transaction %s' % tx.reference or '')

        return res
Пример #24
0
    def do_move_consume(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        move_obj = self.pool.get('stock.move')
        uom_obj = self.pool.get('product.uom')
        production_obj = self.pool.get('mrp.production')
        move_ids = context['active_ids']
        move = move_obj.browse(cr, uid, move_ids[0], context=context)
        production_id = move.raw_material_production_id.id
        production = production_obj.browse(cr, uid, production_id, context=context)
        precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Product Unit of Measure')

        for data in self.browse(cr, uid, ids, context=context):
            qty = uom_obj._compute_qty(cr, uid, data['product_uom'].id, data.product_qty, data.product_id.uom_id.id)
            remaining_qty = move.product_qty - qty
            #check for product quantity is less than previously planned
            if float_compare(remaining_qty, 0, precision_digits=precision) >= 0:
                move_obj.action_consume(cr, uid, move_ids, qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id, context=context)
            else:
                consumed_qty = min(move.product_qty, qty)
                new_moves = move_obj.action_consume(cr, uid, move_ids, consumed_qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id, context=context)
                #consumed more in wizard than previously planned
                extra_more_qty = qty - consumed_qty
                #create new line for a remaining qty of the product
                extra_move_id = production_obj._make_consume_line_from_data(cr, uid, production, data.product_id, data.product_id.uom_id.id, extra_more_qty, context=context)
                move_obj.write(cr, uid, [extra_move_id], {'restrict_lot_id': data.restrict_lot_id.id}, context=context)
                move_obj.action_done(cr, uid, [extra_move_id], context=context)
        return {'type': 'ir.actions.act_window_close'}
    def create(self, vals):
        res = super(AccountPartialReconcile, self).create(vals)
        #check if the reconcilation is full
        #first, gather all journal items involved in the reconciliation just created
        partial_rec_set = OrderedDict.fromkeys([x for x in res])
        aml_set = self.env['account.move.line']
        total_debit = 0
        total_credit = 0
        total_amount_currency = 0
        currency = None
        for partial_rec in partial_rec_set:
            if currency is None:
                currency = partial_rec.currency_id
            for aml in [partial_rec.debit_move_id, partial_rec.credit_move_id]:
                if aml not in aml_set:
                    total_debit += aml.debit
                    total_credit += aml.credit
                    aml_set |= aml
                    if aml.currency_id and aml.currency_id == currency:
                        total_amount_currency += aml.amount_currency
                for x in aml.matched_debit_ids | aml.matched_credit_ids:
                    partial_rec_set[x] = None
        partial_rec_ids = [x.id for x in partial_rec_set.keys()]
        aml_ids = [x.id for x in aml_set]
        #then, if the total debit and credit are equal, or the total amount in currency is 0, the reconciliation is full
        digits_rounding_precision = aml_set[0].company_id.currency_id.rounding
        if float_compare(total_debit, total_credit, precision_rounding=digits_rounding_precision) == 0 \
          or (currency and float_is_zero(total_amount_currency, precision_rounding=currency.rounding)):

            #in that case, mark the reference on the partial reconciliations and the entries
            self.env['account.full.reconcile'].with_context(check_move_validity=False).create({
                'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
                'reconciled_line_ids': [(6, 0, aml_ids)]})
        return res
    def _get_delivered_qty(self):
        self.ensure_one()
        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')

        # 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.
        bom_delivered = {}
        for bom in self.product_id.product_tmpl_id.bom_ids:
            if bom.type != 'phantom':
                continue
            ctx = dict(self.env.context or {})
            ctx.update({'bom_effectivity_date': getattr(self.order_id, 'effective_date', self.order_id.date_order)})
            bom_delivered[bom.id] = False
            product_uom_qty_bom = self.env['product.uom']._compute_qty_obj(self.product_uom, self.product_uom_qty, bom.product_uom)
            bom_exploded = self.env['mrp.bom'].with_context(ctx)._bom_explode(bom, self.product_id, product_uom_qty_bom)[0]
            for bom_line in bom_exploded:
                qty = 0.0
                for move in self.procurement_ids.mapped('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
        if bom_delivered and any(bom_delivered.values()):
            return self.product_uom_qty
        elif bom_delivered:
            return 0.0
        return super(SaleOrderLine, self)._get_delivered_qty()
Пример #27
0
 def check_tax_lines(self, compute_taxes):
     account_invoice_tax = self.env['account.invoice.tax']
     company_currency = self.company_id.currency_id
     if not self.tax_line:
         for tax in compute_taxes.values():
             account_invoice_tax.create(tax)
     else:
         tax_key = []
         precision = self.env['decimal.precision'].precision_get('Account')
         for tax in self.tax_line:
             if tax.manual:
                 continue
             key = self.get_tax_key(tax.id)
             tax_key.append(key)
             if key not in compute_taxes:
                 raise except_orm(_('Warning!'),
                                  _('Global taxes defined,\
                                  but they are not in invoice lines !'))
             base = compute_taxes[key]['base']
             if float_compare(abs(base - tax.base),
                              company_currency.rounding,
                              precision_digits=precision) == 1:
                 raise except_orm(_('Warning!'),
                                  _('Tax base different!\nClick\
                                  on compute to update the tax base.'))
         for key in compute_taxes:
             if self.check_missing_tax():
                 if key not in tax_key:
                     raise except_orm(_('Warning!'),
                                      _('Taxes are missing!\nClick\
                                      on compute button.'))
Пример #28
0
    def _action_procurement_create(self):
        """
        Create procurements based on quantity ordered. If the quantity is increased, new
        procurements are created. If the quantity is decreased, no automated action is taken.
        """
        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
        new_procs = self.env['procurement.order'] #Empty recordset
        for line in self:
            if line.state != 'sale' or not line.product_id._need_procurement():
                continue
            qty = 0.0
            for proc in line.procurement_ids:
                qty += proc.product_qty
            if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0:
                continue

            if not line.order_id.procurement_group_id:
                vals = line.order_id._prepare_procurement_group()
                line.order_id.procurement_group_id = self.env["procurement.group"].create(vals)

            vals = line._prepare_order_line_procurement(group_id=line.order_id.procurement_group_id.id)
            vals['product_qty'] = line.product_uom_qty - qty
            new_proc = self.env["procurement.order"].create(vals)
            new_proc.message_post_with_view('mail.message_origin_link',
                values={'self': new_proc, 'origin': line.order_id},
                subtype_id=self.env.ref('mail.mt_note').id)
            new_procs += new_proc
        new_procs.run()
        return new_procs
Пример #29
0
    def _banklink_form_get_invalid_parameters(self, cr, uid, tx, data, context=None):
        invalid_parameters = []

        acquirer = tx.acquirer_id
        if data.get('VK_SERVICE') not in ('1111', '1911'):
            invalid_parameters.append(('VK_SERVICE', data.get('VK_SERVICE'), '1111 or 1911'))
        if data.get('VK_VERSION') != '008':
            invalid_parameters.append(('VK_VERSION', data.get('VK_VERSION'), '008'))
        if data.get('VK_SND_ID') != acquirer.bank_id:
            invalid_parameters.append(('VK_SND_ID', data.get('VK_SND_ID'), acquirer.bank_id))
        if data.get('VK_REC_ID') != acquirer.VK_SND_ID:
            invalid_parameters.append(('VK_REC_ID', data.get('VK_REC_ID'), acquirer.VK_SND_ID))
        if int(data.get('VK_STAMP')) != tx.sale_order_id.id:
            invalid_parameters.append(('VK_STAMP', data.get('VK_STAMP'), tx.sale_order_id.id))
        if data.get('VK_SERVICE') == '1111':
            if float_compare(float(data.get('VK_AMOUNT', '0.0')), tx.amount, 2) != 0:
                invalid_parameters.append(('VK_AMOUNT', data.get('VK_AMOUNT'), tx.amount))
            if data.get('VK_CURR') != tx.currency_id.name:
                invalid_parameters.append(('VK_CURR', data.get('VK_CURR'), tx.currency_id.name))
            try:
                tx.parse_date(data.get('VK_T_DATETIME'))
            except ValueError:
                invalid_parameters.append(('VK_T_DATETIME', data.get('VK_T_DATETIME'), '<time in DATETIME format, e.g. 2015-03-13T07:21:14+0200>'))
        tx_values = {k: v for k, v in data.iteritems() if k.startswith('VK_')}
        if not acquirer.verify_MAC_string(tx_values, data.get('VK_MAC'), acquirer.get_key('%s_get_bank_cert')):
            invalid_parameters.append(('VK_MAC', '-smth1-', '-smth2-'))

        return invalid_parameters
Пример #30
0
 def _onchange_product_id_check_availability(self):
     if not self.product_id or not self.product_uom_qty or not self.product_uom:
         self.product_packaging = False
         return {}
     if self.product_id.type == "product":
         precision = self.env["decimal.precision"].precision_get("Product Unit of Measure")
         product_qty = self.env["product.uom"]._compute_qty_obj(
             self.product_uom, self.product_uom_qty, self.product_id.uom_id
         )
         if float_compare(self.product_id.virtual_available, product_qty, precision_digits=precision) == -1:
             is_available = self._check_routing()
             if not is_available:
                 warning_mess = {
                     "title": _("Not enough inventory!"),
                     "message": _(
                         "You plan to sell %.2f %s but you only have %.2f %s available!\nThe stock on hand is %.2f %s."
                     )
                     % (
                         self.product_uom_qty,
                         self.product_uom.name,
                         self.product_id.virtual_available,
                         self.product_id.uom_id.name,
                         self.product_id.qty_available,
                         self.product_id.uom_id.name,
                     ),
                 }
                 return {"warning": warning_mess}
     return {}
Пример #31
0
 def clean_outdated_links(self, sale_line):
     missing_part_for_line = self.get_missing_part_for_line(sale_line)
     if missing_part_for_line:
         qty_comp = float_compare(
             sale_line.procurements_not_scheduled_qty,
             0,
             precision_rounding=sale_line.product_uom.rounding)
         if qty_comp <= 0:
             missing_part_for_line.unlink()
         else:
             missing_part_for_line.product_qty = sale_line.procurements_not_scheduled_qty
     else:
         sale_line.increase_or_create_link()
Пример #32
0
 def _validate_asset_values(self):
     for rec in self:
         if not rec.asset_ids or not rec.target_asset_ids:
             raise ValidationError(_('Soure or target assets not filled!'))
         inactive_assets = rec.asset_ids.filtered(lambda l: not l.active)
         if inactive_assets:
             names = ', '.join(inactive_assets.mapped('code'))
             raise ValidationError(
                 _('Following assets are not active!\n%s') % names)
         if float_compare(rec.source_asset_value, rec.target_asset_value,
                          2) != 0:
             raise ValidationError(
                 _('To transfer, source and target value must equal!'))
Пример #33
0
 def test_qif_file_import(self):
     from openerp.tools import float_compare
     qif_file_path = get_module_resource(
         'account_bank_statement_import_qif', 'test_qif_file',
         'test_qif.qif')
     qif_file = open(qif_file_path, 'rb').read().encode('base64')
     bank_statement_improt = self.statement_import_model.with_context(
         journal_id=self.ref('account.bank_journal')).create(
             dict(data_file=qif_file))
     bank_statement_improt.import_file()
     bank_statement = self.statement_line_model.search(
         [('name', '=', 'YOUR LOCAL SUPERMARKET')], limit=1)[0].statement_id
     assert float_compare(bank_statement.balance_end_real, -1896.09, 2) == 0
Пример #34
0
 def check_min_max_qty(self):
     precision = self.env['decimal.precision'].precision_get(
         'Product Unit of Measure')
     for product in self:
         if (not float_is_zero(product.max_qty, precision_digits=precision)
                 and float_compare(product.max_qty,
                                   product.min_qty,
                                   precision_digits=precision) != 1):
             raise ValidationError(
                 _("On product '%s', the maximum quantity (%s) is lower "
                   "than the minimum quantity (%s).") %
                 (product.name_get()[0][1], product.max_qty,
                  product.min_qty))
Пример #35
0
 def wkf_validate_vs_requisition(self):
     """ Amount should not exceed that in Requisition """
     decimal_prec = self.env['decimal.precision']
     precision = decimal_prec.precision_get('Account')
     for po in self:
         # Quotation or Purchase Order
         requisition = po.requisition_id or po.quote_id.requisition_id
         if requisition:
             if float_compare(po.amount_total, requisition.amount_total,
                              precision) == 1:
                 raise ValidationError(
                     _('Confirmed amount exceed Call for Bid amount'))
     return True
Пример #36
0
 def _quants_get_order(self,
                       location,
                       product,
                       quantity,
                       domain=[],
                       orderby='in_date'):
     """ Implementation of removal strategies
         If it can not reserve, it will return a tuple (None, qty)
     """
     domain += location and [('location_id', 'child_of', location.id)] or []
     domain += [('product_id', '=', product.id)]
     if self.env.context.get('force_company'):
         domain += [('company_id', '=',
                     self.env.context.get('force_company'))]
     res = []
     offset = 0
     while float_compare(
             quantity, 0, precision_rounding=product.uom_id.rounding) > 0:
         quants = self.search(domain,
                              order=orderby,
                              limit=10,
                              offset=offset)
         if not quants:
             res.append((None, quantity))
             break
         for quant in quants:
             rounding = product.uom_id.rounding
             if float_compare(quantity,
                              abs(quant.qty),
                              precision_rounding=rounding) >= 0:
                 res += [(quant, abs(quant.qty))]
                 quantity -= abs(quant.qty)
             elif float_compare(quantity, 0.0,
                                precision_rounding=rounding) != 0:
                 res += [(quant, quantity)]
                 quantity = 0
                 break
         offset += 10
     return res
Пример #37
0
 def action_done(self):
     for breakdown in self:
         if float_compare(breakdown.new_policy_amount,
                          breakdown.policy_amount, 2) != 0:
             raise ValidationError(_('Overall policy amount mismatch!'))
         if not breakdown.line_ids:
             raise ValidationError(
                 _('Before you proceed, please click button to '
                   '"Generate Breakdown Lines".'))
         # if not breakdown._validate_breakdown():
         #     continue
         breakdown.generate_budget_control()
         breakdown.write({'state': 'done'})
Пример #38
0
    def compare_amounts(self, amount1, amount2):
        """ Compare `amount1` and `amount2` after rounding them according to
            `self`'s precision. An amount is considered lower/greater than
            another amount if their rounded value is different. This is not the
            same as having a non-zero difference!

            For example 1.432 and 1.431 are equal at 2 digits precision, so this
            method would return 0. However 0.006 and 0.002 are considered
            different (returns 1) because they respectively round to 0.01 and
            0.0, even though 0.006-0.002 = 0.004 which would be considered zero
            at 2 digits precision.
        """
        return float_compare(amount1, amount2, precision_rounding=self.rounding)
Пример #39
0
 def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False):
     res = super(AccountMoveLine,
                 self).reconcile(writeoff_acc_id=writeoff_acc_id,
                                 writeoff_journal_id=writeoff_journal_id)
     account_move_ids = [
         l.move_id.id for l in self if float_compare(
             l.move_id.matched_percentage, 1, precision_digits=5) == 0
     ]
     if account_move_ids:
         expenses = self.env['hr.expense'].search([('account_move_id', 'in',
                                                    account_move_ids)])
         expenses.paid_expenses()
     return res
    def _create_link_for_product(self, prod2move_ids, 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)'''
        op_sol_id = self.env['stock.pack.operation'].search([('id', '=', operation_id)]) \
            .read(['sale_line_id'], load=False)[0]['sale_line_id']
        if not op_sol_id:
            return super(ExpeditionByOrderLinePicking,
                         self)._create_link_for_product(
                             prod2move_ids, operation_id, product_id, qty)

        qty_to_assign = qty
        product = self.env['product.product'].browse([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:
                i = 0
                for move_data in prod2move_ids[product_id]:
                    if move_data['move']['sale_line_id'] == op_sol_id:
                        qty_on_link, prod2move_ids = self._create_link_for_index(
                            prod2move_ids,
                            operation_id,
                            i,
                            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)
                        break
                    else:
                        i += 1
                else:
                    break
        result_comp = qtyassign_cmp == 0
        return result_comp, prod2move_ids
Пример #41
0
    def form_feedback(self, cr, uid, data, acquirer_name, context=None):
        """ Override to confirm the sale order, if defined, and if the transaction
        is done. """
        tx = None
        res = super(PaymentTransaction, self).form_feedback(cr,
                                                            uid,
                                                            data,
                                                            acquirer_name,
                                                            context=context)

        # fetch the tx, check its state, confirm the potential SO
        tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
        if hasattr(self, tx_find_method_name):
            tx = getattr(self, tx_find_method_name)(cr,
                                                    uid,
                                                    data,
                                                    context=context)

        if tx and tx.sale_order_id and tx.sale_order_id.state in [
                'draft', 'sent'
        ]:
            amount_matches = float_compare(tx.amount,
                                           tx.sale_order_id.amount_total,
                                           2) == 0
            if amount_matches:
                if tx.state == 'done' and tx.acquirer_id.auto_confirm == 'at_pay_confirm':
                    _logger.info(
                        '<%s> transaction completed, auto-confirming order %s (ID %s)',
                        acquirer_name, tx.sale_order_id.name,
                        tx.sale_order_id.id)
                    self.pool['sale.order'].action_confirm(
                        cr,
                        SUPERUSER_ID, [tx.sale_order_id.id],
                        context=dict(context, send_email=True))
                elif tx and tx.state not in [
                        'cancel', 'error'
                ] and tx.sale_order_id and tx.sale_order_id.state in ['draft']:
                    _logger.info(
                        '<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)',
                        acquirer_name, tx.sale_order_id.name,
                        tx.sale_order_id.id)
                    self.pool['sale.order'].force_quotation_send(
                        cr,
                        SUPERUSER_ID, [tx.sale_order_id.id],
                        context=context)
            else:
                _logger.warning(
                    '<%s> transaction MISMATCH for order %s (ID %s)',
                    acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)

        return res
Пример #42
0
    def _po_info(self,
                 cr,
                 uid,
                 ids,
                 field_names=None,
                 arg=False,
                 context=None):
        """ Finds the requisition related PO info.
        @return: Dictionary of values
        """
        if not field_names:
            field_names = []
        if context is None:
            context = {}
        res = {}
        for id in ids:
            res[id] = {}.fromkeys(field_names, 0.0)
        for req_line in self.browse(cr, uid, ids, context=context):
            generated_po = False
            req_qty = req_line.product_qty
            po_qty = 0
            product_qty_remain = req_line.product_qty
            po_qty_str = ''
            if req_line.po_lines_ids:
                uom_obj = self.pool.get('product.uom')
                for po_line in req_line.po_lines_ids:
                    if po_line.state != 'cancel':
                        ctx_uom = context.copy()
                        ctx_uom['raise-exception'] = False
                        uom_po_qty = uom_obj._compute_qty_obj(cr, uid, po_line.product_uom, po_line.product_qty, \
                                                              req_line.product_uom_id, context=ctx_uom)
                        po_qty += uom_po_qty
                        po_qty_str += (
                            (po_qty_str or '') and '; '
                        ) + '%s(%s)@%s' % (po_line.product_qty, uom_po_qty,
                                           po_line.order_id.name)


#                po_finished = float_compare(po_qty, req_qty, precision_rounding=req_line.product_uom_id.rounding)
                po_finished = float_compare(req_qty,
                                            po_qty,
                                            precision_rounding=1)
                generated_po = (po_finished <= 0)
                if generated_po:
                    product_qty_remain = 0
                else:
                    product_qty_remain = req_qty - po_qty
            res[req_line.id]['generated_po'] = generated_po
            res[req_line.id]['product_qty_remain'] = product_qty_remain
            res[req_line.id]['po_info'] = po_qty_str
        return res
Пример #43
0
    def form_feedback(self, data, acquirer_name):
        """ Override to confirm the sale order, if defined, and if the transaction
        is done. """
        tx = None
        res = super(PaymentTransaction,
                    self).form_feedback(data, acquirer_name)

        # fetch the tx, check its state, confirm the potential SO
        try:
            tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
            if hasattr(self, tx_find_method_name):
                tx = getattr(self, tx_find_method_name)(data)
            _logger.info(
                '<%s> transaction processed: tx ref:%s, tx amount: %s',
                acquirer_name, tx.reference if tx else 'n/a',
                tx.amount if tx else 'n/a')

            if tx and tx.sale_order_id and tx.sale_order_id.state in [
                    'draft', 'sent'
            ]:
                # verify SO/TX match, excluding tx.fees which are currently not included in SO
                amount_matches = float_compare(tx.amount,
                                               tx.sale_order_id.amount_total,
                                               2) == 0
                if amount_matches:
                    if tx.state == 'done' and tx.acquirer_id.auto_confirm == 'at_pay_confirm':
                        _logger.info(
                            '<%s> transaction completed, auto-confirming order %s (ID %s)',
                            acquirer_name, tx.sale_order_id.name,
                            tx.sale_order_id.id)
                        tx.sale_order_id.with_context(
                            send_email=True).action_confirm()
                    elif tx.state not in [
                            'cancel', 'error'
                    ] and tx.sale_order_id.state == 'draft':
                        _logger.info(
                            '<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)',
                            acquirer_name, tx.sale_order_id.name,
                            tx.sale_order_id.id)
                        tx.sale_order_id.force_quotation_send()
                else:
                    _logger.warning(
                        '<%s> transaction MISMATCH for order %s (ID %s)',
                        acquirer_name, tx.sale_order_id.name,
                        tx.sale_order_id.id)
        except Exception:
            _logger.exception(
                'Fail to confirm the order or send the confirmation email%s',
                tx and ' for the transaction %s' % tx.reference or '')

        return res
Пример #44
0
    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
            uom=False, qty_uos=0, uos=False, name='', partner_id=False,
            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):
        context = context or {}
        product_uom_obj = self.pool.get('product.uom')
        partner_obj = self.pool.get('res.partner')
        product_obj = self.pool.get('product.product')
        warning = {}
        res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,
            uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,
            lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)

        if not product:
            res['value'].update({'product_packaging': False})
            return res

        #update of result obtained in super function
        product_obj = product_obj.browse(cr, uid, product, context=context)
        res['value']['delay'] = (product_obj.sale_delay or 0.0)
        res['value']['type'] = product_obj.procure_method

        #check if product is available, and if not: raise an error
        uom2 = False
        if uom:
            uom2 = product_uom_obj.browse(cr, uid, uom, context=context)
            if product_obj.uom_id.category_id.id != uom2.category_id.id:
                uom = False
        if not uom2:
            uom2 = product_obj.uom_id

        # Calling product_packaging_change function after updating UoM
        res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context)
        res['value'].update(res_packing.get('value', {}))
        warning_msgs = res_packing.get('warning') and res_packing['warning']['message'] or ''
        compare_qty = float_compare(product_obj.virtual_available, qty, precision_rounding=uom2.rounding)
        if (product_obj.type=='product') and int(compare_qty) == -1 \
           and (product_obj.procure_method=='make_to_stock'):
            warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \
                    (qty, uom2.name,
                     max(0,product_obj.virtual_available), uom2.name,
                     max(0,product_obj.qty_available), uom2.name)
            warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n"

        #update of warning messages
        if warning_msgs:
            warning = {
                       'title': _('Configuration Error!'),
                       'message' : warning_msgs
                    }
        res.update({'warning': warning})
        return res
    def _compute_procure_recommended(self):
        procurement_model = self.env['procurement.order']
        for op in self:
            op.procure_recommended_date = \
                procurement_model._get_orderpoint_date_planned(
                    op, datetime.today())
            procure_recommended_qty = 0.0
            prods = procurement_model._product_virtual_get(op)
            if prods is None:
                continue
            if float_compare(prods, op.product_min_qty,
                             precision_rounding=op.product_uom.rounding) < 0:
                qty = max(op.product_min_qty, op.product_max_qty) - prods
                reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
                if float_compare(
                        reste, 0.0,
                        precision_rounding=op.product_uom.rounding) > 0:
                    qty += op.qty_multiple - reste

                if float_compare(
                        qty, 0.0,
                        precision_rounding=op.product_uom.rounding) <= 0:
                    continue

                qty -= op.subtract_procurements(op)

                qty_rounded = float_round(
                    qty, precision_rounding=op.product_uom.rounding)
                if qty_rounded > 0:
                    procure_recommended_qty = qty_rounded
                if op.procure_uom_id:
                    product_qty = op.procure_uom_id._compute_qty(
                        op.product_id.uom_id.id, procure_recommended_qty,
                        op.procure_uom_id.id)
                else:
                    product_qty = procure_recommended_qty

                op.procure_recommended_qty = product_qty
Пример #46
0
    def _check_sum(self, cr, uid, landed_cost, context=None):
        """
        Will check if each cost line its valuation lines sum to the correct amount
        and if the overall total amount is correct also
        """
        if context is None:
            context = {}
        currency_obj = self.pool.get('res.currency')
        costcor = {}
        tot = 0
        for valuation_line in landed_cost.valuation_adjustment_lines:
            if costcor.get(valuation_line.cost_line_id):
                costcor[valuation_line.
                        cost_line_id] += valuation_line.additional_landed_cost
            else:
                costcor[valuation_line.
                        cost_line_id] = valuation_line.additional_landed_cost
            tot += valuation_line.additional_landed_cost

        prec = self.pool['decimal.precision'].precision_get(cr, uid, 'Account')
        local_context = context.copy()
        # float_compare returns 0 for equal amounts
        res = not bool(
            float_compare(tot, landed_cost.amount_total,
                          precision_digits=prec))
        for costl in costcor.keys():
            local_context['date'] = landed_cost.date
            price_unit = currency_obj.compute(
                cr,
                uid,
                costl.currency_id.id,
                landed_cost.company_id.currency_id.id,
                costl.price_unit,
                context=local_context)
            if float_compare(costcor[costl], price_unit,
                             precision_digits=prec):
                res = False
        return res
Пример #47
0
    def action_consume(self, cr, uid, ids, product_qty, location_id=False, restrict_lot_id=False, restrict_partner_id=False,
                       consumed_for=False, context=None):
        """ Consumed product with specific quantity from specific source location.
        @param product_qty: Consumed/produced product quantity (= in quantity of UoM of product)
        @param location_id: Source location
        @param restrict_lot_id: optionnal parameter that allows to restrict the choice of quants on this specific lot
        @param restrict_partner_id: optionnal parameter that allows to restrict the choice of quants to this specific partner
        @param consumed_for: optionnal parameter given to this function to make the link between raw material consumed and produced product, for a better traceability
        @return: New lines created if not everything was consumed for this line
        """
        if context is None:
            context = {}
        res = []
        production_obj = self.pool.get('mrp.production')

        if product_qty <= 0:
            raise UserError(_('Please provide proper quantity.'))
        #because of the action_confirm that can create extra moves in case of phantom bom, we need to make 2 loops
        ids2 = []
        for move in self.browse(cr, uid, ids, context=context):
            if move.state == 'draft':
                ids2.extend(self.action_confirm(cr, uid, [move.id], context=context))
            else:
                ids2.append(move.id)

        prod_orders = set()
        for move in self.browse(cr, uid, ids2, context=context):
            prod_orders.add(move.raw_material_production_id.id or move.production_id.id)
            move_qty = move.product_qty
            if move_qty <= 0:
                raise UserError(_('Cannot consume a move with negative or zero quantity.'))
            quantity_rest = move_qty - product_qty
            # Compare with numbers of move uom as we want to avoid a split with 0 qty
            quantity_rest_uom = move.product_uom_qty - self.pool.get("product.uom")._compute_qty_obj(cr, uid, move.product_id.uom_id, product_qty, move.product_uom)
            if float_compare(quantity_rest_uom, 0, precision_rounding=move.product_uom.rounding) != 0:
                new_mov = self.split(cr, uid, move, quantity_rest, context=context)
                res.append(new_mov)
            vals = {'restrict_lot_id': restrict_lot_id,
                    'restrict_partner_id': restrict_partner_id,
                    'consumed_for': consumed_for}
            if location_id:
                vals.update({'location_id': location_id})
            self.write(cr, uid, [move.id], vals, context=context)
        # Original moves will be the quantities consumed, so they need to be done
        self.action_done(cr, uid, ids2, context=context)
        if res:
            self.action_assign(cr, uid, res, context=context)
        if prod_orders:
            production_obj.signal_workflow(cr, uid, list(prod_orders), 'button_produce')
        return res
Пример #48
0
 def write(self, values):
     lines = False
     if 'product_uom_qty' in values:
         precision = self.env['decimal.precision'].precision_get(
             'Product Unit of Measure')
         lines = self.filtered(
             lambda r: r.state == 'sale' and float_compare(
                 r.product_uom_qty,
                 values['product_uom_qty'],
                 precision_digits=precision) == -1)
     result = super(SaleOrderLine, self).write(values)
     if lines:
         lines._action_procurement_create()
     return result
Пример #49
0
 def wkf_validate_vs_quotation(self):
     """ Case Central Purchase, quotation amount should not exceed """
     decimal_prec = self.env['decimal.precision']
     precision = decimal_prec.precision_get('Account')
     for requisition in self:
         if not requisition.is_central_purchase:
             continue
         total = sum([o.amount_total for o in requisition.purchase_ids])
         if float_compare(total, requisition.amount_total,
                          precision) == 1:
             raise ValidationError(
                 _('Total quotation amount exceed Call for Bid amount')
             )
     return True
 def create(self, vals):
     uom_id = vals.get('product_uom')
     product_id = vals.get('product_id')
     move_qty = float(vals.get('product_uom_qty', 0))
     uom = uom_id and self.env['product.uom'].search([('id', '=', uom_id)]) or \
         self.env['product.product'].search([('id', '=', product_id)]).uom_id or False
     negative_move = uom and float_compare(
         move_qty, 0.0,
         precision_rounding=uom.rounding) <= 0 or move_qty <= 0
     if negative_move:
         raise exceptions.except_orm(
             _(u"Error!"),
             _(u"You are not allowed to create a negative or null move."))
     return super(StockQuant, self).create(vals)
Пример #51
0
 def _amount_currency_change(self):
     if (self.currency_id and self.amount_currency and not self.credit
             and not self.debit):
         date = self.date or None
         amount_company_currency = self.currency_id.with_context(
             date=date).compute(self.amount_currency,
                                self.env.user.company_id.currency_id)
         precision = self.env['decimal.precision'].precision_get('Account')
         if float_compare(amount_company_currency,
                          0,
                          precision_digits=precision) == -1:
             self.debit = amount_company_currency * -1
         else:
             self.credit = amount_company_currency
Пример #52
0
 def proforma_voucher(self):
     for rec in self:
         if rec.type != 'payment':
             continue
         if rec.force_pay:
             continue
         # A payment, and not force pay, check for balance and throw error
         if float_compare(rec.amount, rec.journal_balance, 2) > 0:
             raise ValidationError(
                 _('Pay amount (%s) exceed balance (%s)!\n') %
                 ('{:,.2f}'.format(rec.amount),
                  '{:,.2f}'.format(rec.journal_balance)))
     res = super(AccountVoucher, self).proforma_voucher()
     return res
Пример #53
0
 def split_not_totally_consumed_moves(self, dict_reservation_target):
     for move in dict_reservation_target.keys():
         prec = move.product_id.uom_id.rounding
         required_qty = sum([
             quant_tuple[1] for quant_tuple in dict_reservation_target[move]
             ['reservations']
         ])
         if float_compare(move.product_qty,
                          required_qty,
                          precision_rounding=prec) > 0:
             move.split(
                 move,
                 float_round(move.product_qty - required_qty,
                             precision_rounding=prec))
Пример #54
0
 def check_product_uom_qty(self, product_id):
     if self.product_uom_qty:
         if self.product_id.type == 'product':
             if self.product_id.virtual_available_days < 5 or self.product_id.consumption_per_day < self.product_uom_qty:
                 compare_qty = float_compare(
                     self.product_id.virtual_available_netto,
                     self.product_uom_qty,
                     precision_rounding=self.product_uom.rounding)
                 if compare_qty == -1:
                     raise Warning(_('Missing stock:\n%s: You plan to sell %.2f %s but you only have %.2f %s available!\nThe real stock is %.2f %s. (without reservations)') % \
                         (self.product_id.name_get()[0][1],
                         self.product_uom_qty, self.product_uom.name,
                         max(0,self.product_id.virtual_available_netto), self.product_uom.name,
                         max(0,self.product_id.qty_available), self.product_uom.name))
Пример #55
0
    def test_coda_file_import(self):
        self.bank_statement_import.import_file()
        bank_st_record = self.bank_statement_model.search([
            ('name', '=', 'TBNK/2012/135')
        ])[0]
        self.assertEqual(
            float_compare(bank_st_record.balance_start,
                          11812.70,
                          precision_digits=2), 0)
        self.assertEqual(
            float_compare(bank_st_record.balance_end_real,
                          13646.05,
                          precision_digits=2), 0)
        # check line name
        self.assertEqual(
            'MEDEDELING', bank_st_record.line_ids[0].name,
            'Name should be the communication if no structured communication '
            'found')
        self.assertEqual(
            '+++240/2838/42818+++', bank_st_record.line_ids[1].name,
            'Name should be the structured communication id provided')
        for line in bank_st_record.line_ids[2:5]:
            self.assertEqual(
                'KBC-INVESTERINGSKREDIET 737-6543210-21', line.name,
                'Name should be the communication of the related '
                'globalisation line for details line')

        # check the note
        self.assertEqual(
            'Counter Party: PARTNER 2\n'
            'Counter Party Account: BE61310126985517\n'
            'Communication: +++240/2838/42818+++ '
            '001PARTNER 2MOLENSTRAAT 60 9340 LEDE',
            bank_st_record.line_ids[1].note,
            'The note should contain informations on the counter part '
            'but also the communication for the information records that '
            'refer the movement record')
Пример #56
0
 def parse_csv_order(self, order_file, partner):
     assert partner, 'missing partner'
     fileobj = TemporaryFile('w+')
     fileobj.write(order_file)
     fileobj.seek(0)
     reader = unicodecsv.reader(fileobj,
                                delimiter=';',
                                quoting=unicodecsv.QUOTE_MINIMAL,
                                encoding='utf8')
     i = 0
     parsed_order = {
         'partner': {
             'recordset': partner
         },
         'lines': [],
     }
     precision = self.env['decimal.precision'].precision_get('Product UoS')
     for line in reader:
         logger.debug('csv line %d: %s', i, line)
         i += 1
         if len(line) < 2:
             raise UserError(
                 _("Error on line %d of the CSV file: this line should have "
                   "a product code and a quantity, separated by a "
                   "semi-colon.") % i)
         if not line[0]:
             raise UserError(
                 _("Error on line %d of the CSV file: the line should start "
                   "with a product code") % i)
         try:
             qty = float(line[1])
         except:
             raise UserError(
                 _("Error on line %d of the CSV file: the second column "
                   "should contain a quantity. The quantity should use dot "
                   "as decimal separator and shouldn't have any thousand "
                   "separator") % i)
         if float_compare(qty, 0, precision_digits=precision) != 1:
             raise UserError(
                 _("Error on line %d of the CSV file: the quantity should "
                   "be strictly positive") % i)
         parsed_order['lines'].append({
             'qty': qty,
             'product': {
                 'code': line[0]
             },
         })
     fileobj.close()
     return parsed_order
Пример #57
0
    def _prepare_suggest_line(self, product_id, qty_dict):
        porderline_id = False
        porderlines = self.env['purchase.order.line'].search(
            [('state', 'not in', ('draft', 'cancel')),
             ('product_id', '=', product_id)],
            order='id desc',
            limit=1)
        # I cannot filter on 'date_order' because it is not a stored field
        porderline_id = porderlines and porderlines[0].id or False
        future_qty = qty_dict['virtual_available'] + qty_dict['draft_po_qty']
        if float_compare(
                qty_dict['max_qty'],
                qty_dict['min_qty'],
                precision_rounding=qty_dict['product'].uom_id.rounding) == 1:
            # order to go up to qty_max
            qty_to_order = qty_dict['max_qty'] - future_qty
        else:
            # order to go up to qty_min
            qty_to_order = qty_dict['min_qty'] - future_qty

        sline = {
            'company_id':
            qty_dict['orderpoint'] and qty_dict['orderpoint'].company_id.id,
            'product_id':
            product_id,
            'seller_id':
            qty_dict['product'].seller_id.id or False,
            'qty_available':
            qty_dict['qty_available'],
            'incoming_qty':
            qty_dict['incoming_qty'],
            'outgoing_qty':
            qty_dict['outgoing_qty'],
            'draft_po_qty':
            qty_dict['draft_po_qty'],
            'orderpoint_id':
            qty_dict['orderpoint'] and qty_dict['orderpoint'].id,
            'location_id':
            self.location_id.id,
            'min_qty':
            qty_dict['min_qty'],
            'max_qty':
            qty_dict['max_qty'],
            'last_po_line_id':
            porderline_id,
            'qty_to_order':
            qty_to_order,
        }
        return sline
Пример #58
0
 def move_products(self):
     self.ensure_one()
     lines = self.quant_line_ids + self.package_line_ids
     lines.check_quantities()
     lines.check_data_active()
     is_manual_op = self.is_manual_op or lines.force_is_manual_op()
     packages = self.env['stock.quant.package']
     for package_line in self.package_line_ids:
         packages |= package_line.package_id
     quants_to_move = packages.get_content()
     quants_to_move = self.env['stock.quant'].browse(quants_to_move)
     move_items = {}
     # Let's add package quants
     for quant in quants_to_move:
         move_items = quant.partial_move(move_items, quant.product_id,
                                         quant.qty)
     # Let's move quant lines
     for quant_line in self.quant_line_ids:
         domain = [
             ('product_id', '=', quant_line.product_id.id),
             ('location_id', '=', quant_line.location_id.id),
             ('package_id', '=',
              quant_line.package_id and quant_line.package_id.id or False),
             ('lot_id', '=', quant_line.lot_id and quant_line.lot_id.id
              or False),
             ('product_id.uom_id', '=',
              quant_line.uom_id and quant_line.uom_id.id or False),
             ('id', 'not in', quants_to_move.ids)
         ]
         quants = self.env['stock.quant'].search(domain,
                                                 order='in_date, qty')
         if quants:
             move_items = quants.partial_move(move_items,
                                              quant_line.product_id,
                                              quant_line.qty)
             quants_to_move |= quants
     if any([
             float_compare(
                 quant.qty,
                 0,
                 precision_rounding=quant.product_id.uom_id.rounding) < 0
             for quant in quants_to_move
     ]):
         raise exceptions.except_orm(
             _("error"), _("Impossible to move a negative quant"))
     new_picking = quants_to_move.with_context(mail_notrack=True). \
         move_to(self.global_dest_loc, self.picking_type_id, move_items=move_items, is_manual_op=is_manual_op,
                 filling_method=self.filling_method)
     return new_picking.open_picking_form(is_manual_op)
Пример #59
0
    def action_consume_cancel(self, cr, uid, ids, context=None):
        """ Cancels the moves and if all moves are cancelled it cancels the picking.
        @return: True
        """
        if not ids:
            return True

        new_move = self.browse(cr, uid, ids, context)[0]

        sm_ids = self.search(cr,
                             uid, [('move_dest_id', '=', new_move.id)],
                             context=context)
        sp_picking = False
        if sm_ids:
            for move in self.browse(cr, uid, sm_ids):
                sp_picking = move.picking_id
                if move.state == 'done':
                    self.write(cr, uid, [move.id], {'state': 'cancel'})
                else:
                    self.action_cancel(cr, uid, [move.id], context=context)
        if sp_picking:
            mrp_obj = self.pool.get('mrp.production')
            mo_ids = mrp_obj.search(cr,
                                    uid, [('picking_id', '=', sp_picking.id)],
                                    context=context)
            if mo_ids:
                prod_line_obj = self.pool.get('mrp.production.product.line')
                ml_ids = prod_line_obj.search(
                    cr,
                    uid, [('production_id', '=', mo_ids[0]),
                          ('product_id', '=', new_move.product_id.id)],
                    context=context)
                if ml_ids:
                    prod_line = prod_line_obj.browse(cr, uid, ml_ids)[0]
                    compare = float_compare(prod_line.product_qty,
                                            new_move.product_qty,
                                            precision_rounding=4)
                    if compare == 0:
                        prod_line_obj.unlink(cr,
                                             uid, [prod_line.id],
                                             context=context)
                    elif compare > 0:
                        prod_line_obj.write(
                            cr, uid, [prod_line.id], {
                                'product_qty':
                                prod_line.product_qty - new_move.product_qty
                            })

        self.action_cancel(cr, uid, [new_move.id], context=context)
Пример #60
0
 def post_import_validation(self):
     for rec in self:
         # 1) total_budget and planned_amount should equal
         total_budget = sum(rec.plan_line_ids.mapped('total_budget'))
         planned_amount = sum(rec.plan_line_ids.mapped('planned_amount'))
         if float_compare(total_budget, planned_amount, 2) != 0:
             raise ValidationError(
                 _("Excel's total budget not equal planned amount"))
         # 2) If external line has income_section_id, remove it.
         if rec.plan_line_ids.\
                 filtered(lambda l: l.charge_type == 'external').\
                 mapped('income_section_id'):
             raise ValidationError(
                 _('For line with external charge type, '
                   'income section is not allowed'))