예제 #1
0
 def action_pos_session_close(self):
     # Close CashBox
     for session in self:
         company_id = session.config_id.company_id.id
         ctx = dict(self.env.context,
                    force_company=company_id,
                    company_id=company_id)
         ctx_notrack = dict(ctx, mail_notrack=True)
         for st in session.statement_ids:
             if abs(st.difference) > st.journal_id.amount_authorized_diff:
                 # The pos manager can close statements with maximums.
                 if not self.user_has_groups(
                         "point_of_sale.group_pos_manager"):
                     raise UserError(
                         _("Your ending balance is too different from the theoretical cash closing (%.2f), the maximum allowed is: %.2f. You can contact your manager to force it."
                           ) % (st.difference,
                                st.journal_id.amount_authorized_diff))
             if (st.journal_id.type not in ['bank', 'cash']):
                 raise UserError(
                     _("The journal type for your payment method should be bank or cash."
                       ))
             st.with_context(ctx_notrack).sudo().button_confirm_bank()
     self.with_context(ctx)._confirm_orders()
     self.write({'state': 'closed'})
     return {
         'type': 'ir.actions.client',
         'name': 'Point of Sale Menu',
         'tag': 'reload',
         'params': {
             'menu_id': self.env.ref('point_of_sale.menu_point_root').id
         },
     }
예제 #2
0
 def action_repair_cancel(self):
     if self.filtered(lambda repair: repair.state == 'done'):
         raise UserError(_("Cannot cancel completed repairs."))
     if any(repair.invoiced for repair in self):
         raise UserError(_('The repair order is already invoiced.'))
     self.mapped('operations').write({'state': 'cancel'})
     return self.write({'state': 'cancel'})
예제 #3
0
    def button_start(self):
        self.ensure_one()
        # As button_start is automatically called in the new view
        if self.state in ('done', 'cancel'):
            return True

        # Need a loss in case of the real time exceeding the expected
        timeline = self.env['mrp.workcenter.productivity']
        if self.duration < self.duration_expected:
            loss_id = self.env['mrp.workcenter.productivity.loss'].search([('loss_type','=','productive')], limit=1)
            if not len(loss_id):
                raise UserError(_("You need to define at least one productivity loss in the category 'Productivity'. Create one from the Manufacturing app, menu: Configuration / Productivity Losses."))
        else:
            loss_id = self.env['mrp.workcenter.productivity.loss'].search([('loss_type','=','performance')], limit=1)
            if not len(loss_id):
                raise UserError(_("You need to define at least one productivity loss in the category 'Performance'. Create one from the Manufacturing app, menu: Configuration / Productivity Losses."))
        for workorder in self:
            if workorder.production_id.state != 'progress':
                workorder.production_id.write({
                    'state': 'progress',
                    'date_start': datetime.now(),
                })
            timeline.create({
                'workorder_id': workorder.id,
                'workcenter_id': workorder.workcenter_id.id,
                'description': _('Time Tracking: ')+self.env.user.name,
                'loss_id': loss_id[0].id,
                'date_start': datetime.now(),
                'user_id': self.env.user.id
            })
        return self.write({'state': 'progress',
                    'date_start': datetime.now(),
        })
예제 #4
0
 def create_advice(self):
     for run in self:
         if run.available_advice:
             raise UserError(_("Payment advice already exists for %s, 'Set to Draft' to create a new advice.") % (run.name,))
         company = self.env.user.company_id
         advice = self.env['hr.payroll.advice'].create({
                     'batch_id': run.id,
                     'company_id': company.id,
                     'name': run.name,
                     'date': run.date_end,
                     'bank_id': company.partner_id.bank_ids and company.partner_id.bank_ids[0].bank_id.id or False
                 })
         for slip in run.slip_ids:
             # TODO is it necessary to interleave the calls ?
             slip.action_payslip_done()
             if not slip.employee_id.bank_account_id or not slip.employee_id.bank_account_id.acc_number:
                 raise UserError(_('Please define bank account for the %s employee') % (slip.employee_id.name))
             payslip_line = self.env['hr.payslip.line'].search([('slip_id', '=', slip.id), ('code', '=', 'NET')], limit=1)
             if payslip_line:
                 self.env['hr.payroll.advice.line'].create({
                     'advice_id': advice.id,
                     'name': slip.employee_id.bank_account_id.acc_number,
                     'ifsc_code': slip.employee_id.bank_account_id.bank_bic or '',
                     'employee_id': slip.employee_id.id,
                     'bysal': payslip_line.total
                 })
     self.write({'available_advice': True})
예제 #5
0
 def write(self, vals):
     if 'uom_id' in vals:
         new_uom = self.env['uom.uom'].browse(vals['uom_id'])
         updated = self.filtered(
             lambda template: template.uom_id != new_uom)
         done_moves = self.env['stock.move'].search(
             [('product_id', 'in', updated.with_context(
                 active_test=False).mapped('product_variant_ids').ids)],
             limit=1)
         if done_moves:
             raise UserError(
                 _("You cannot change the unit of measure as there are already stock moves for this product. If you want to change the unit of measure, you should rather archive this product and create a new one."
                   ))
     if 'type' in vals and vals['type'] != 'product' and sum(
             self.mapped('nbr_reordering_rules')) != 0:
         raise UserError(
             _('You still have some active reordering rules on this product. Please archive or delete them first.'
               ))
     if any('type' in vals and vals['type'] != prod_tmpl.type
            for prod_tmpl in self):
         existing_move_lines = self.env['stock.move.line'].search([
             ('product_id', 'in', self.mapped('product_variant_ids').ids),
             ('state', 'in', ['partially_available', 'assigned']),
         ])
         if existing_move_lines:
             raise UserError(
                 _("You can not change the type of a product that is currently reserved on a stock move. If you need to change the type, you should first unreserve the stock move."
                   ))
     if 'type' in vals and vals['type'] != 'product' and self.filtered(
             lambda p: p.type == 'product' and not float_is_zero(
                 p.qty_available, precision_rounding=p.uom_id.rounding)):
         raise UserError(
             _("Available quantity should be set to zero before changing type"
               ))
     return super(ProductTemplate, self).write(vals)
예제 #6
0
파일: pos.py 프로젝트: metricsw/swerp
    def write(self, vals):
        has_been_posted = False
        for order in self:
            if order.company_id._is_accounting_unalterable():
                # write the hash and the secure_sequence_number when posting or invoicing an pos.order
                if vals.get('state') in ['paid', 'done', 'invoiced']:
                    has_been_posted = True

                # restrict the operation in case we are trying to write a forbidden field
                if (order.state in ['paid', 'done', 'invoiced']
                        and set(vals).intersection(ORDER_FIELDS)):
                    raise UserError(
                        _('According to the French law, you cannot modify a point of sale order. Forbidden fields: %s.'
                          ) % ', '.join(ORDER_FIELDS))
                # restrict the operation in case we are trying to overwrite existing hash
                if (order.l10n_fr_hash and 'l10n_fr_hash' in vals) or (
                        order.l10n_fr_secure_sequence_number
                        and 'l10n_fr_secure_sequence_number' in vals):
                    raise UserError(
                        _('You cannot overwrite the values ensuring the inalterability of the point of sale.'
                          ))
        res = super(pos_order, self).write(vals)
        # write the hash and the secure_sequence_number when posting or invoicing a pos order
        if has_been_posted:
            for order in self.filtered(
                    lambda o: o.company_id._is_accounting_unalterable() and
                    not (o.l10n_fr_secure_sequence_number or o.l10n_fr_hash)):
                new_number = order.company_id.l10n_fr_pos_cert_sequence_id.next_by_id(
                )
                vals_hashing = {
                    'l10n_fr_secure_sequence_number': new_number,
                    'l10n_fr_hash': order._get_new_hash(new_number)
                }
                res |= super(pos_order, order).write(vals_hashing)
        return res
예제 #7
0
    def write(self, vals):
        has_been_posted = False
        for move in self:
            if move.company_id._is_accounting_unalterable():
                # write the hash and the secure_sequence_number when posting an account.move
                if vals.get('state') == 'posted':
                    has_been_posted = True

                # restrict the operation in case we are trying to write a forbidden field
                if (move.state == "posted"
                        and set(vals).intersection(MOVE_FIELDS)):
                    raise UserError(
                        _("According to the French law, you cannot modify a journal entry in order for its posted data to be updated or deleted. Unauthorized field: %s."
                          ) % ', '.join(MOVE_FIELDS))
                # restrict the operation in case we are trying to overwrite existing hash
                if (move.l10n_fr_hash and 'l10n_fr_hash' in vals) or (
                        move.l10n_fr_secure_sequence_number
                        and 'l10n_fr_secure_sequence_number' in vals):
                    raise UserError(
                        _('You cannot overwrite the values ensuring the inalterability of the accounting.'
                          ))
        res = super(AccountMove, self).write(vals)
        # write the hash and the secure_sequence_number when posting an account.move
        if has_been_posted:
            for move in self.filtered(
                    lambda m: m.company_id._is_accounting_unalterable() and
                    not (m.l10n_fr_secure_sequence_number or m.l10n_fr_hash)):
                new_number = move.company_id.l10n_fr_secure_sequence_id.next_by_id(
                )
                vals_hashing = {
                    'l10n_fr_secure_sequence_number': new_number,
                    'l10n_fr_hash': move._get_new_hash(new_number)
                }
                res |= super(AccountMove, move).write(vals_hashing)
        return res
예제 #8
0
    def act_update(self):
        '''
        Function called by the wizard.
        '''
        flag, gengo = self.gengo_authentication()
        if not flag:
            raise UserError(gengo)
        for wizard in self:
            supported_langs = self.env[
                'ir.translation']._get_all_supported_languages()
            language = self.env[
                'ir.translation']._get_gengo_corresponding_language(
                    wizard.lang_id.code)
            if language not in supported_langs:
                raise UserError(
                    _('This language is not supported by the Gengo translation services.'
                      ))

            ctx = self.env.context.copy()
            ctx['gengo_language'] = wizard.lang_id.id
            if wizard.sync_limit > 200 or wizard.sync_limit < 1:
                raise UserError(
                    _('The number of terms to sync should be between 1 to 200 to work with Gengo translation services.'
                      ))
            if wizard.sync_type in ['send', 'both']:
                self.with_context(ctx)._sync_request(wizard.sync_limit)
            if wizard.sync_type in ['receive', 'both']:
                self.with_context(ctx)._sync_response(wizard.sync_limit)
        return {'type': 'ir.actions.act_window_close'}
예제 #9
0
    def _action_done(self):
        self.product_price_update_before_done()
        res = super(StockMove, self)._action_done()
        for move in res:
            # Apply restrictions on the stock move to be able to make
            # consistent accounting entries.
            if move._is_in() and move._is_out():
                raise UserError(_("The move lines are not in a consistent state: some are entering and other are leaving the company."))
            company_src = move.mapped('move_line_ids.location_id.company_id')
            company_dst = move.mapped('move_line_ids.location_dest_id.company_id')
            try:
                if company_src:
                    company_src.ensure_one()
                if company_dst:
                    company_dst.ensure_one()
            except ValueError:
                raise UserError(_("The move lines are not in a consistent states: they do not share the same origin or destination company."))
            if company_src and company_dst and company_src.id != company_dst.id:
                raise UserError(_("The move lines are not in a consistent states: they are doing an intercompany in a single step while they should go through the intercompany transit location."))
            move._run_valuation()
        for move in res.filtered(lambda m: m.product_id.valuation == 'real_time' and (m._is_in() or m._is_out() or m._is_dropshipped() or m._is_dropshipped_returned())):
            move._account_entry_move()

        products_to_vacuum = defaultdict(lambda: self.env['product.product'])
        for move in res.filtered(lambda m: m.product_id.valuation == 'real_time' and m._is_in() and (m.product_id.property_cost_method == 'fifo' or m.product_id.categ_id.property_cost_method == 'fifo')):
            products_to_vacuum[move.company_id.id] += move.product_id
        for company_id in products_to_vacuum:
            moves_to_vacuum = self.search(
                [('product_id', 'in', products_to_vacuum[company_id].ids), ('remaining_qty', '<', 0)] + self._get_all_base_domain(company_id=company_id))
            moves_to_vacuum._fifo_vacuum()

        return res
예제 #10
0
    def print_checks(self):
        """ Check that the recordset is valid, set the payments state to sent and call print_checks() """
        # Since this method can be called via a client_action_multi, we need to make sure the received records are what we expect
        self = self.filtered(lambda r: r.payment_method_id.code == 'check_printing' and r.state != 'reconciled')

        if len(self) == 0:
            raise UserError(_("Payments to print as a checks must have 'Check' selected as payment method and "
                              "not have already been reconciled"))
        if any(payment.journal_id != self[0].journal_id for payment in self):
            raise UserError(_("In order to print multiple checks at once, they must belong to the same bank journal."))

        if not self[0].journal_id.check_manual_sequencing:
            # The wizard asks for the number printed on the first pre-printed check
            # so payments are attributed the number of the check the'll be printed on.
            last_printed_check = self.search([
                ('journal_id', '=', self[0].journal_id.id),
                ('check_number', '!=', 0)], order="check_number desc", limit=1)
            next_check_number = last_printed_check and last_printed_check.check_number + 1 or 1
            return {
                'name': _('Print Pre-numbered Checks'),
                'type': 'ir.actions.act_window',
                'res_model': 'print.prenumbered.checks',
                'view_type': 'form',
                'view_mode': 'form',
                'target': 'new',
                'context': {
                    'payment_ids': self.ids,
                    'default_next_check_number': next_check_number,
                }
            }
        else:
            self.filtered(lambda r: r.state == 'draft').post()
            return self.do_print_checks()
예제 #11
0
    def _get_accounting_data_for_valuation(self):
        """ Return the accounts and journal to use to post Journal Entries for
        the real-time valuation of the quant. """
        self.ensure_one()
        accounts_data = self.product_id.product_tmpl_id.get_product_accounts()

        if self.location_id.valuation_out_account_id:
            acc_src = self.location_id.valuation_out_account_id.id
        else:
            acc_src = accounts_data['stock_input'].id

        if self.location_dest_id.valuation_in_account_id:
            acc_dest = self.location_dest_id.valuation_in_account_id.id
        else:
            acc_dest = accounts_data['stock_output'].id

        acc_valuation = accounts_data.get('stock_valuation', False)
        if acc_valuation:
            acc_valuation = acc_valuation.id
        if not accounts_data.get('stock_journal', False):
            raise UserError(_('You don\'t have any stock journal defined on your product category, check if you have installed a chart of accounts.'))
        if not acc_src:
            raise UserError(_('Cannot find a stock input account for the product %s. You must define one on the product category, or on the location, before processing this operation.') % (self.product_id.display_name))
        if not acc_dest:
            raise UserError(_('Cannot find a stock output account for the product %s. You must define one on the product category, or on the location, before processing this operation.') % (self.product_id.display_name))
        if not acc_valuation:
            raise UserError(_('You don\'t have any stock valuation account defined on your product category. You must define one before processing this operation.'))
        journal_id = accounts_data['stock_journal'].id
        return journal_id, acc_src, acc_dest, acc_valuation
예제 #12
0
 def action_in_progress(self):
     self.ensure_one()
     if not all(obj.line_ids for obj in self):
         raise UserError(
             _("You cannot confirm agreement '%s' because there is no product line."
               ) % self.name)
     if self.type_id.quantity_copy == 'none' and self.vendor_id:
         for requisition_line in self.line_ids:
             if requisition_line.price_unit <= 0.0:
                 raise UserError(
                     _('You cannot confirm the blanket order without price.'
                       ))
             if requisition_line.product_qty <= 0.0:
                 raise UserError(
                     _('You cannot confirm the blanket order without quantity.'
                       ))
             requisition_line.create_supplier_info()
         self.write({'state': 'ongoing'})
     else:
         self.write({'state': 'in_progress'})
     # Set the sequence number regarding the requisition type
     if self.name == 'New':
         if self.is_quantity_copy != 'none':
             self.name = self.env['ir.sequence'].next_by_code(
                 'purchase.requisition.purchase.tender')
         else:
             self.name = self.env['ir.sequence'].next_by_code(
                 'purchase.requisition.blanket.order')
예제 #13
0
    def open_statement(self):
        self.ensure_one()
        BankStatement = self.env['account.bank.statement']
        journals = self.env['account.journal'].search([('journal_user', '=',
                                                        True)])
        if not journals:
            raise UserError(
                _('You have to define which payment method must be available in the point of sale by reusing existing bank and cash through "Accounting / Configuration / Journals / Journals". Select a journal and check the field "PoS Payment Method" from the "Point of Sale" tab. You can also create new payment methods directly from menu "PoS Backend / Configuration / Payment Methods".'
                  ))

        for journal in journals:
            if journal.sequence_id:
                number = journal.sequence_id.next_by_id()
            else:
                raise UserError(_("No sequence defined on the journal"))
            BankStatement += BankStatement.create({
                'journal_id': journal.id,
                'user_id': self.env.uid,
                'name': number
            })

        tree_id = self.env.ref('account.view_bank_statement_tree').id
        form_id = self.env.ref('account.view_bank_statement_form').id
        search_id = self.env.ref('account.view_bank_statement_search').id

        return {
            'type': 'ir.actions.act_window',
            'name': _('List of Cash Registers'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'account.bank.statement',
            'domain': str([('id', 'in', BankStatement.ids)]),
            'views': [(tree_id, 'tree'), (form_id, 'form')],
            'search_view_id': search_id,
        }
예제 #14
0
    def _satisfy_condition(self, localdict):
        """
        @param contract_id: id of hr.contract to be tested
        @return: returns True if the given rule match the condition for the given contract. Return False otherwise.
        """
        self.ensure_one()

        if self.condition_select == 'none':
            return True
        elif self.condition_select == 'range':
            try:
                result = safe_eval(self.condition_range, localdict)
                return self.condition_range_min <= result and result <= self.condition_range_max or False
            except:
                raise UserError(
                    _('Wrong range condition defined for salary rule %s (%s).')
                    % (self.name, self.code))
        else:  # python code
            try:
                safe_eval(self.condition_python,
                          localdict,
                          mode='exec',
                          nocopy=True)
                return 'result' in localdict and localdict['result'] or False
            except:
                raise UserError(
                    _('Wrong python condition defined for salary rule %s (%s).'
                      ) % (self.name, self.code))
예제 #15
0
파일: ir_module.py 프로젝트: metricsw/swerp
    def button_upgrade(self):
        Dependency = self.env['ir.module.module.dependency']
        self.update_list()

        todo = list(self)
        i = 0
        while i < len(todo):
            module = todo[i]
            i += 1
            if module.state not in ('installed', 'to upgrade'):
                raise UserError(_("Can not upgrade module '%s'. It is not installed.") % (module.name,))
            self.check_external_dependencies(module.name, 'to upgrade')
            for dep in Dependency.search([('name', '=', module.name)]):
                if dep.module_id.state == 'installed' and dep.module_id not in todo:
                    todo.append(dep.module_id)

        self.browse(module.id for module in todo).write({'state': 'to upgrade'})

        to_install = []
        for module in todo:
            for dep in module.dependencies_id:
                if dep.state == 'unknown':
                    raise UserError(_('You try to upgrade the module %s that depends on the module: %s.\nBut this module is not available in your system.') % (module.name, dep.name,))
                if dep.state == 'uninstalled':
                    to_install += self.search([('name', '=', dep.name)]).ids

        self.browse(to_install).button_install()
        return dict(ACTION_DICT, name=_('Apply Schedule Upgrade'))
예제 #16
0
파일: ir_module.py 프로젝트: metricsw/swerp
    def _state_update(self, newstate, states_to_update, level=100):
        if level < 1:
            raise UserError(_('Recursion error in modules dependencies !'))

        # whether some modules are installed with demo data
        demo = False

        for module in self:
            # determine dependency modules to update/others
            update_mods, ready_mods = self.browse(), self.browse()
            for dep in module.dependencies_id:
                if dep.state == 'unknown':
                    raise UserError(_("You try to install module '%s' that depends on module '%s'.\nBut the latter module is not available in your system.") % (module.name, dep.name,))
                if dep.depend_id.state == newstate:
                    ready_mods += dep.depend_id
                else:
                    update_mods += dep.depend_id

            # update dependency modules that require it, and determine demo for module
            update_demo = update_mods._state_update(newstate, states_to_update, level=level-1)
            module_demo = module.demo or update_demo or any(mod.demo for mod in ready_mods)
            demo = demo or module_demo

            if module.state in states_to_update:
                # check dependencies and update module itself
                self.check_external_dependencies(module.name, newstate)
                module.write({'state': newstate, 'demo': module_demo})

        return demo
예제 #17
0
    def _create_returns(self):
        # TODO sle: the unreserve of the next moves could be less brutal
        for return_move in self.product_return_moves.mapped('move_id'):
            return_move.move_dest_ids.filtered(lambda m: m.state not in ('done', 'cancel'))._do_unreserve()

        # create new picking for returned products
        picking_type_id = self.picking_id.picking_type_id.return_picking_type_id.id or self.picking_id.picking_type_id.id
        new_picking = self.picking_id.copy({
            'move_lines': [],
            'picking_type_id': picking_type_id,
            'state': 'draft',
            'origin': _("Return of %s") % self.picking_id.name,
            'location_id': self.picking_id.location_dest_id.id,
            'location_dest_id': self.location_id.id})
        new_picking.message_post_with_view('mail.message_origin_link',
            values={'self': new_picking, 'origin': self.picking_id},
            subtype_id=self.env.ref('mail.mt_note').id)
        returned_lines = 0
        for return_line in self.product_return_moves:
            if not return_line.move_id:
                raise UserError(_("You have manually created product lines, please delete them to proceed."))
            # TODO sle: float_is_zero?
            if return_line.quantity:
                returned_lines += 1
                vals = self._prepare_move_default_values(return_line, new_picking)
                r = return_line.move_id.copy(vals)
                vals = {}

                # +--------------------------------------------------------------------------------------------------------+
                # |       picking_pick     <--Move Orig--    picking_pack     --Move Dest-->   picking_ship
                # |              | returned_move_ids              ↑                                  | returned_move_ids
                # |              ↓                                | return_line.move_id              ↓
                # |       return pick(Add as dest)          return toLink                    return ship(Add as orig)
                # +--------------------------------------------------------------------------------------------------------+
                move_orig_to_link = return_line.move_id.move_dest_ids.mapped('returned_move_ids')
                # link to original move
                move_orig_to_link |= return_line.move_id
                # link to siblings of original move, if any
                move_orig_to_link |= return_line.move_id\
                    .mapped('move_dest_ids').filtered(lambda m: m.state not in ('cancel'))\
                    .mapped('move_orig_ids').filtered(lambda m: m.state not in ('cancel'))
                move_dest_to_link = return_line.move_id.move_orig_ids.mapped('returned_move_ids')
                # link to children of originally returned moves, if any. Note that the use of
                # 'return_line.move_id.move_orig_ids.returned_move_ids.move_orig_ids.move_dest_ids'
                # instead of 'return_line.move_id.move_orig_ids.move_dest_ids' prevents linking a
                # return directly to the destination moves of its parents. However, the return of
                # the return will be linked to the destination moves.
                move_dest_to_link |= return_line.move_id.move_orig_ids.mapped('returned_move_ids')\
                    .mapped('move_orig_ids').filtered(lambda m: m.state not in ('cancel'))\
                    .mapped('move_dest_ids').filtered(lambda m: m.state not in ('cancel'))
                vals['move_orig_ids'] = [(4, m.id) for m in move_orig_to_link]
                vals['move_dest_ids'] = [(4, m.id) for m in move_dest_to_link]
                r.write(vals)
        if not returned_lines:
            raise UserError(_("Please specify at least one non-zero quantity."))

        new_picking.action_confirm()
        new_picking.action_assign()
        return new_picking.id, picking_type_id
예제 #18
0
    def done(self):
        pickings = self.mapped('picking_ids').filtered(
            lambda picking: picking.state not in ('cancel', 'done'))
        if any(picking.state not in ('assigned') for picking in pickings):
            raise UserError(
                _('Some pickings are still waiting for goods. Please check or force their availability before setting this batch to done.'
                  ))
        for picking in pickings:
            picking.message_post(
                body=
                "<b>%s:</b> %s <a href=#id=%s&view_type=form&model=stock.picking.batch>%s</a>"
                % (_("Transferred by"), _("Batch Picking"),
                   picking.batch_id.id, picking.batch_id.name))

        picking_to_backorder = self.env['stock.picking']
        picking_without_qty_done = self.env['stock.picking']
        for picking in pickings:
            if all([x.qty_done == 0.0 for x in picking.move_line_ids]):
                # If no lots when needed, raise error
                picking_type = picking.picking_type_id
                if (picking_type.use_create_lots
                        or picking_type.use_existing_lots):
                    for ml in picking.move_line_ids:
                        if ml.product_id.tracking != 'none':
                            raise UserError(
                                _('Some products require lots/serial numbers.')
                            )
                # Check if we need to set some qty done.
                picking_without_qty_done |= picking
            elif picking._check_backorder():
                picking_to_backorder |= picking
            else:
                picking.action_done()
        if picking_without_qty_done:
            view = self.env.ref('stock.view_immediate_transfer')
            wiz = self.env['stock.immediate.transfer'].create({
                'pick_ids': [(4, p.id) for p in picking_without_qty_done],
                'pick_to_backorder_ids':
                [(4, p.id) for p in picking_to_backorder],
            })
            return {
                'name': _('Immediate Transfer?'),
                'type': 'ir.actions.act_window',
                'view_type': 'form',
                'view_mode': 'form',
                'res_model': 'stock.immediate.transfer',
                'views': [(view.id, 'form')],
                'view_id': view.id,
                'target': 'new',
                'res_id': wiz.id,
                'context': self.env.context,
            }
        if picking_to_backorder:
            return picking_to_backorder.action_generate_backorder_wizard()
        # Change the state only if there is no other action (= wizard) waiting.
        self.write({'state': 'done'})
        return True
예제 #19
0
    def action_unbuild(self):
        self.ensure_one()
        if self.product_id.tracking != 'none' and not self.lot_id.id:
            raise UserError(_('You should provide a lot number for the final product.'))

        if self.mo_id:
            if self.mo_id.state != 'done':
                raise UserError(_('You cannot unbuild a undone manufacturing order.'))

        consume_move = self._generate_consume_moves()[0]
        consume_move._action_confirm()
        produce_moves = self._generate_produce_moves()
        produce_moves._action_confirm()

        if any(produce_move.has_tracking != 'none' and not self.mo_id for produce_move in produce_moves):
            raise UserError(_('Some of your components are tracked, you have to specify a manufacturing order in order to retrieve the correct components.'))

        if consume_move.has_tracking != 'none':
            self.env['stock.move.line'].create({
                'move_id': consume_move.id,
                'lot_id': self.lot_id.id,
                'qty_done': consume_move.product_uom_qty,
                'product_id': consume_move.product_id.id,
                'product_uom_id': consume_move.product_uom.id,
                'location_id': consume_move.location_id.id,
                'location_dest_id': consume_move.location_dest_id.id,
            })
        else:
            consume_move.quantity_done = consume_move.product_uom_qty
        consume_move._action_done()

        # TODO: Will fail if user do more than one unbuild with lot on the same MO. Need to check what other unbuild has aready took
        for produce_move in produce_moves:
            if produce_move.has_tracking != 'none':
                original_move = self.mo_id.move_raw_ids.filtered(lambda move: move.product_id == produce_move.product_id)
                needed_quantity = produce_move.product_uom_qty
                for move_lines in original_move.mapped('move_line_ids').filtered(lambda ml: ml.lot_produced_id == self.lot_id):
                    # Iterate over all move_lines until we unbuilded the correct quantity.
                    taken_quantity = min(needed_quantity, move_lines.qty_done)
                    if taken_quantity:
                        self.env['stock.move.line'].create({
                            'move_id': produce_move.id,
                            'lot_id': move_lines.lot_id.id,
                            'qty_done': taken_quantity,
                            'product_id': produce_move.product_id.id,
                            'product_uom_id': move_lines.product_uom_id.id,
                            'location_id': produce_move.location_id.id,
                            'location_dest_id': produce_move.location_dest_id.id,
                        })
                        needed_quantity -= taken_quantity
            else:
                produce_move.quantity_done = produce_move.product_uom_qty
        produce_moves._action_done()
        produced_move_line_ids = produce_moves.mapped('move_line_ids').filtered(lambda ml: ml.qty_done > 0)
        consume_move.move_line_ids.write({'produce_line_ids': [(6, 0, produced_move_line_ids.ids)]})

        return self.write({'state': 'done'})
예제 #20
0
    def _merge(self, partner_ids, dst_partner=None, extra_checks=True):
        """ private implementation of merge partner
            :param partner_ids : ids of partner to merge
            :param dst_partner : record of destination res.partner
            :param extra_checks: pass False to bypass extra sanity check (e.g. email address)
        """
        # super-admin can be used to bypass extra checks
        if self.env.user._is_admin():
            extra_checks = False

        Partner = self.env['res.partner']
        partner_ids = Partner.browse(partner_ids).exists()
        if len(partner_ids) < 2:
            return

        if len(partner_ids) > 3:
            raise UserError(_("For safety reasons, you cannot merge more than 3 contacts together. You can re-open the wizard several times if needed."))

        # check if the list of partners to merge contains child/parent relation
        child_ids = self.env['res.partner']
        for partner_id in partner_ids:
            child_ids |= Partner.search([('id', 'child_of', [partner_id.id])]) - partner_id
        if partner_ids & child_ids:
            raise UserError(_("You cannot merge a contact with one of his parent."))

        if extra_checks and len(set(partner.email for partner in partner_ids)) > 1:
            raise UserError(_("All contacts must have the same email. Only the Administrator can merge contacts with different emails."))

        # remove dst_partner from partners to merge
        if dst_partner and dst_partner in partner_ids:
            src_partners = partner_ids - dst_partner
        else:
            ordered_partners = self._get_ordered_partner(partner_ids.ids)
            dst_partner = ordered_partners[-1]
            src_partners = ordered_partners[:-1]
        _logger.info("dst_partner: %s", dst_partner.id)

        # FIXME: is it still required to make and exception for account.move.line since accounting v9.0 ?
        if extra_checks and 'account.move.line' in self.env and self.env['account.move.line'].sudo().search([('partner_id', 'in', [partner.id for partner in src_partners])]):
            raise UserError(_("Only the destination contact may be linked to existing Journal Items. Please ask the Administrator if you need to merge several contacts linked to existing Journal Items."))

        # Make the company of all related users consistent with destination partner company
        if dst_partner.company_id:
            partner_ids.mapped('user_ids').sudo().write({
                'company_ids': [(4, dst_partner.company_id.id)],
                'company_id': dst_partner.company_id.id
            })

        # call sub methods to do the merge
        self._update_foreign_keys(src_partners, dst_partner)
        self._update_reference_fields(src_partners, dst_partner)
        self._update_values(src_partners, dst_partner)

        self._log_merge_operation(src_partners, dst_partner)

        # delete source partner, since they are merged
        src_partners.unlink()
예제 #21
0
파일: pos.py 프로젝트: metricsw/swerp
    def _check_hash_integrity(self, company_id):
        """Checks that all posted or invoiced pos orders have still the same data as when they were posted
        and raises an error with the result.
        """
        def build_order_info(order):
            entry_reference = _('(Receipt ref.: %s)')
            order_reference_string = order.pos_reference and entry_reference % order.pos_reference or ''
            return [
                ctx_tz(order,
                       'date_order'), order.l10n_fr_secure_sequence_number,
                order.name, order_reference_string,
                ctx_tz(order, 'write_date')
            ]

        orders = self.search([('state', 'in', ['paid', 'done', 'invoiced']),
                              ('company_id', '=', company_id),
                              ('l10n_fr_secure_sequence_number', '!=', 0)],
                             order="l10n_fr_secure_sequence_number ASC")

        if not orders:
            raise UserError(
                _('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS'
                  ) % self.env.user.company_id.name)
        previous_hash = u''
        start_order_info = []
        for order in orders:
            if order.l10n_fr_hash != order._compute_hash(
                    previous_hash=previous_hash):
                raise UserError(
                    _('Corrupted data on point of sale order with id %s.') %
                    order.id)
            previous_hash = order.l10n_fr_hash

        orders_sorted_date = orders.sorted(lambda o: o.date_order)
        start_order_info = build_order_info(orders_sorted_date[0])
        end_order_info = build_order_info(orders_sorted_date[-1])

        report_dict = {
            'start_order_name': start_order_info[2],
            'start_order_ref': start_order_info[3],
            'start_order_date': start_order_info[0],
            'end_order_name': end_order_info[2],
            'end_order_ref': end_order_info[3],
            'end_order_date': end_order_info[0]
        }

        # Raise on success
        raise UserError(
            _('''Successful test !

                         The point of sale orders are guaranteed to be in their original and inalterable state
                         From: %(start_order_name)s %(start_order_ref)s recorded on %(start_order_date)s
                         To: %(end_order_name)s %(end_order_ref)s recorded on %(end_order_date)s

                         For this report to be legally meaningful, please download your certification from your customer account on Swerp.com (Only for Swerp Enterprise users).'''
              ) % report_dict)
예제 #22
0
파일: ir_module.py 프로젝트: metricsw/swerp
    def button_install(self):
        # domain to select auto-installable (but not yet installed) modules
        auto_domain = [('state', '=', 'uninstalled'), ('auto_install', '=', True)]

        # determine whether an auto-install module must be installed:
        #  - all its dependencies are installed or to be installed,
        #  - at least one dependency is 'to install'
        install_states = frozenset(('installed', 'to install', 'to upgrade'))
        def must_install(module):
            states = set(dep.state for dep in module.dependencies_id)
            return states <= install_states and 'to install' in states

        modules = self
        while modules:
            # Mark the given modules and their dependencies to be installed.
            modules._state_update('to install', ['uninstalled'])

            # Determine which auto-installable modules must be installed.
            modules = self.search(auto_domain).filtered(must_install)

        # the modules that are installed/to install/to upgrade
        install_mods = self.search([('state', 'in', list(install_states))])

        # check individual exclusions
        install_names = {module.name for module in install_mods}
        for module in install_mods:
            for exclusion in module.exclusion_ids:
                if exclusion.name in install_names:
                    msg = _('Modules "%s" and "%s" are incompatible.')
                    raise UserError(msg % (module.shortdesc, exclusion.exclusion_id.shortdesc))

        # check category exclusions
        def closure(module):
            todo = result = module
            while todo:
                result |= todo
                todo = todo.mapped('dependencies_id.depend_id')
            return result

        exclusives = self.env['ir.module.category'].search([('exclusive', '=', True)])
        for category in exclusives:
            # retrieve installed modules in category and sub-categories
            categories = category.search([('id', 'child_of', category.ids)])
            modules = install_mods.filtered(lambda mod: mod.category_id in categories)
            # the installation is valid if all installed modules in categories
            # belong to the transitive dependencies of one of them
            if modules and not any(modules <= closure(module) for module in modules):
                msg = _('You are trying to install incompatible modules in category "%s":')
                labels = dict(self.fields_get(['state'])['state']['selection'])
                raise UserError("\n".join([msg % category.name] + [
                    "- %s (%s)" % (module.shortdesc, labels[module.state])
                    for module in modules
                ]))

        return dict(ACTION_DICT, name=_('Install'))
예제 #23
0
 def _assert_primary_email(self):
     if not hasattr(self, "_primary_email") or \
             not isinstance(self._primary_email, (list, tuple)) or \
             not len(self._primary_email) == 1:
         raise UserError(
             _('Invalid primary email field on model %s') % self._name)
     field_name = self._primary_email[0]
     if field_name not in self._fields or self._fields[
             field_name].type != 'char':
         raise UserError(
             _('Invalid primary email field on model %s') % self._name)
예제 #24
0
파일: ir_module.py 프로젝트: metricsw/swerp
 def button_uninstall(self):
     if 'base' in self.mapped('name'):
         raise UserError(_("The `base` module cannot be uninstalled"))
     if not all(state in ('installed', 'to upgrade') for state in self.mapped('state')):
         raise UserError(_(
             "One or more of the selected modules have already been uninstalled, if you "
             "believe this to be an error, you may try again later or contact support."
         ))
     deps = self.downstream_dependencies()
     (self + deps).write({'state': 'to remove'})
     return dict(ACTION_DICT, name=_('Uninstall'))
예제 #25
0
    def button_validate(self):
        if any(cost.state != 'draft' for cost in self):
            raise UserError(_('Only draft landed costs can be validated'))
        if any(not cost.valuation_adjustment_lines for cost in self):
            raise UserError(
                _('No valuation adjustments lines. You should maybe recompute the landed costs.'
                  ))
        if not self._check_sum():
            raise UserError(
                _('Cost and adjustments lines do not match. You should maybe recompute the landed costs.'
                  ))

        for cost in self:
            move = self.env['account.move']
            move_vals = {
                'journal_id': cost.account_journal_id.id,
                'date': cost.date,
                'ref': cost.name,
                'line_ids': [],
            }
            for line in cost.valuation_adjustment_lines.filtered(
                    lambda line: line.move_id):
                # Prorate the value at what's still in stock
                cost_to_add = (
                    line.move_id.remaining_qty /
                    line.move_id.product_qty) * line.additional_landed_cost

                new_landed_cost_value = line.move_id.landed_cost_value + line.additional_landed_cost
                line.move_id.write({
                    'landed_cost_value':
                    new_landed_cost_value,
                    'value':
                    line.move_id.value + line.additional_landed_cost,
                    'remaining_value':
                    line.move_id.remaining_value + cost_to_add,
                    'price_unit':
                    (line.move_id.value + line.additional_landed_cost) /
                    line.move_id.product_qty,
                })
                # `remaining_qty` is negative if the move is out and delivered proudcts that were not
                # in stock.
                qty_out = 0
                if line.move_id._is_in():
                    qty_out = line.move_id.product_qty - line.move_id.remaining_qty
                elif line.move_id._is_out():
                    qty_out = line.move_id.product_qty
                move_vals['line_ids'] += line._create_accounting_entries(
                    move, qty_out)

            move = move.create(move_vals)
            cost.write({'state': 'done', 'account_move_id': move.id})
            move.post()
        return True
예제 #26
0
    def phone_parse(number, country_code):
        try:
            phone_nbr = phonenumbers.parse(number, region=country_code, keep_raw_input=True)
        except phonenumbers.phonenumberutil.NumberParseException as e:
            raise UserError(_('Unable to parse %s:\n%s') % (number, e))

        if not phonenumbers.is_possible_number(phone_nbr):
            raise UserError(_('Impossible number %s: probably invalid number of digits') % number)
        if not phonenumbers.is_valid_number(phone_nbr):
            raise UserError(_('Invalid number %s: probably incorrect prefix') % number)

        return phone_nbr
예제 #27
0
 def get_access_token(self, scope=None):
     Config = self.env['ir.config_parameter'].sudo()
     google_drive_refresh_token = Config.get_param(
         'google_drive_refresh_token')
     user_is_admin = self.env['res.users'].browse(
         self.env.user.id)._is_admin()
     if not google_drive_refresh_token:
         if user_is_admin:
             dummy, action_id = self.env[
                 'ir.model.data'].get_object_reference(
                     'base_setup', 'action_general_configuration')
             msg = _(
                 "You haven't configured 'Authorization Code' generated from google, Please generate and configure it ."
             )
             raise RedirectWarning(msg, action_id,
                                   _('Go to the configuration panel'))
         else:
             raise UserError(
                 _("Google Drive is not yet configured. Please contact your administrator."
                   ))
     google_drive_client_id = Config.get_param('google_drive_client_id')
     google_drive_client_secret = Config.get_param(
         'google_drive_client_secret')
     #For Getting New Access Token With help of old Refresh Token
     data = {
         'client_id': google_drive_client_id,
         'refresh_token': google_drive_refresh_token,
         'client_secret': google_drive_client_secret,
         'grant_type': "refresh_token",
         'scope': scope or 'https://www.googleapis.com/auth/drive'
     }
     headers = {"Content-type": "application/x-www-form-urlencoded"}
     try:
         req = requests.post(GOOGLE_TOKEN_ENDPOINT,
                             data=data,
                             headers=headers,
                             timeout=TIMEOUT)
         req.raise_for_status()
     except requests.HTTPError:
         if user_is_admin:
             dummy, action_id = self.env[
                 'ir.model.data'].get_object_reference(
                     'base_setup', 'action_general_configuration')
             msg = _(
                 "Something went wrong during the token generation. Please request again an authorization code ."
             )
             raise RedirectWarning(msg, action_id,
                                   _('Go to the configuration panel'))
         else:
             raise UserError(
                 _("Google Drive is not yet configured. Please contact your administrator."
                   ))
     return req.json().get('access_token')
예제 #28
0
파일: event.py 프로젝트: metricsw/swerp
 def button_reg_close(self):
     """ Close Registration """
     today = fields.Datetime.now()
     if self.event_id.date_begin <= today and self.event_id.state == 'confirm':
         self.write({'state': 'done', 'date_closed': today})
     elif self.event_id.state == 'draft':
         raise UserError(
             _("You must wait the event confirmation before doing this action."
               ))
     else:
         raise UserError(
             _("You must wait the event starting day before doing this action."
               ))
예제 #29
0
파일: pos_box.py 프로젝트: metricsw/swerp
 def _run(self, records):
     for box in self:
         for record in records:
             if not record.journal_id:
                 raise UserError(
                     _("Please check that the field 'Journal' is set on the Bank Statement"
                       ))
             if not record.journal_id.company_id.transfer_account_id:
                 raise UserError(
                     _("Please check that the field 'Transfer Account' is set on the company."
                       ))
             box._create_bank_statement_line(record)
     return {}
예제 #30
0
    def check_finished_move_lots(self):
        produce_move = self.production_id.move_finished_ids.filtered(lambda x: x.product_id == self.product_id and x.state not in ('done', 'cancel'))
        if produce_move and produce_move.product_id.tracking != 'none':
            if not self.lot_id:
                raise UserError(_('You need to provide a lot for the finished product.'))
            existing_move_line = produce_move.move_line_ids.filtered(lambda x: x.lot_id == self.lot_id)
            if existing_move_line:
                if self.product_id.tracking == 'serial':
                    raise UserError(_('You cannot produce the same serial number twice.'))
                produced_qty = self.product_uom_id._compute_quantity(self.product_qty, existing_move_line.product_uom_id)
                existing_move_line.product_uom_qty += produced_qty
                existing_move_line.qty_done += produced_qty
            else:
                location_dest_id = produce_move.location_dest_id.get_putaway_strategy(self.product_id).id or produce_move.location_dest_id.id
                vals = {
                  'move_id': produce_move.id,
                  'product_id': produce_move.product_id.id,
                  'production_id': self.production_id.id,
                  'product_uom_qty': self.product_qty,
                  'product_uom_id': self.product_uom_id.id,
                  'qty_done': self.product_qty,
                  'lot_id': self.lot_id.id,
                  'location_id': produce_move.location_id.id,
                  'location_dest_id': location_dest_id,
                }
                self.env['stock.move.line'].create(vals)

        for pl in self.produce_line_ids:
            if pl.qty_done:
                if pl.product_id.tracking != 'none' and not pl.lot_id:
                    raise UserError(_('Please enter a lot or serial number for %s !' % pl.product_id.display_name))
                if not pl.move_id:
                    # Find move_id that would match
                    move_id = self.production_id.move_raw_ids.filtered(lambda m: m.product_id == pl.product_id and m.state not in ('done', 'cancel'))
                    if move_id:
                        pl.move_id = move_id
                    else:
                        # create a move and put it in there
                        order = self.production_id
                        pl.move_id = self.env['stock.move'].create({
                                    'name': order.name,
                                    'product_id': pl.product_id.id,
                                    'product_uom': pl.product_uom_id.id,
                                    'location_id': order.location_src_id.id,
                                    'location_dest_id': self.product_id.property_stock_production.id,
                                    'raw_material_production_id': order.id,
                                    'group_id': order.procurement_group_id.id,
                                    'origin': order.name,
                                    'state': 'confirmed'})
                pl.move_id._generate_consumed_move_line(pl.qty_done, self.lot_id, lot=pl.lot_id)
        return True