Esempio n. 1
0
class AccountBankPayment(models.Model):
    _inherit = 'account.bank.payment'

    multiple_reconcile_ids = fields.One2many(
        'account.bank.payment.multiple.reconcile',
        'bank_payment_id',
        string='Reconcile Lines',
        readonly=True,
        states={'draft': [('readonly', False)]},
    )
    writeoff_amount = fields.Float(
        string="Writeoff Amount",
        readonly=True,
        compute="_compute_writeoff_amount",
        help="Computed as the difference between the amount\
        stated in the voucher and the sum of allocation\
        on the voucher lines.",
    )
    payment_difference_amount = fields.Float(
        string="Difference Amount",
        readonly=True,
        compute="_compute_writeoff_amount",
        help="Computed as the difference between the amount\
        stated in the voucher and the sum of allocation\
        on the voucher lines.",
    )
    total_amount = fields.Float(
        string="Computed Total Amount",
        copy=False,
    )
    manual_total_amount = fields.Float(
        string="Total Amount",
        readonly=True,
        default=0.0,
        states={'draft': [('readonly', False)]},
        required=True,
        copy=False,
    )
    move_id = fields.Many2one(
        'account.move',
        string='Journal Entry',
        readonly=True,
        copy=False,
    )

    @api.multi
    def validate_bank_payment(self):
        for payment in self:
            if float_compare(payment.writeoff_amount, 0.0, 2) != 0:
                raise ValidationError(
                    _('Writeoff Amount must be 0.0 to validate!'))
        res = super(AccountBankPayment, self).validate_bank_payment()
        return res

    @api.multi
    @api.depends('manual_total_amount')
    def _compute_bank_payment(self):
        res = super(AccountBankPayment, self)._compute_bank_payment()
        for payment in self:
            payment.total_amount = payment.manual_total_amount
        return res

    @api.multi
    @api.depends('total_amount', 'multiple_reconcile_ids',
                 'multiple_reconcile_ids.amount')
    def _compute_writeoff_amount(self):
        for payment in self:
            total = 0.0
            currency_none_same_company_id = False
            if payment.company_id.currency_id != payment.currency_id:
                currency_none_same_company_id = payment.currency_id.id
            for line in payment.bank_intransit_ids:
                if currency_none_same_company_id:
                    total += line.amount_currency
                else:
                    total += line.credit
            writeoffline_amount = 0.0
            if payment.multiple_reconcile_ids:
                writeoffline_amount =\
                    sum([l.amount for l in payment.multiple_reconcile_ids])
            payment.payment_difference_amount = payment.total_amount - total
            payment.writeoff_amount = (payment.total_amount -
                                       writeoffline_amount - total)

    @api.model
    def _create_writeoff_move_line_hook(self, move):
        super(AccountBankPayment, self)._create_writeoff_move_line_hook(move)
        if self.payment_difference_amount != 0.0:
            MoveLine = self.env['account.move.line']
            if self.payment_difference_amount != 0.0 and \
                    self.multiple_reconcile_ids:
                for writeofline in self.multiple_reconcile_ids:
                    move_line_val = \
                        self._prepare_writeoff_move_line(writeofline)
                    move_line_val['move_id'] = move.id
                    MoveLine.create(move_line_val)
        return True

    @api.model
    def _do_reconcile(self, to_reconcile_lines):
        if self.payment_difference_amount != 0.0 and \
                self.multiple_reconcile_ids:
            for reconcile_lines in to_reconcile_lines:
                reconcile_lines.reconcile_partial(type='manual')
            return True
        else:
            return super(AccountBankPayment,
                         self)._do_reconcile(to_reconcile_lines)

    @api.onchange('writeoff_amount')
    def onchange_writeoff_amount(self):
        for payment in self:
            if payment.writeoff_amount == 0.0:
                payment.multiple_reconcile_ids = [(6, 0, [])]

    @api.model
    def _prepare_counterpart_move_lines_vals(self, payment, total_credit,
                                             total_amount_currency):
        vals = super(AccountBankPayment, self).\
            _prepare_counterpart_move_lines_vals(payment, total_credit,
                                                 total_amount_currency)
        if self.payment_difference_amount != 0.0 and \
                self.multiple_reconcile_ids:
            vals['credit'] = self.total_amount
        return vals

    @api.model
    def _prepare_writeoff_move_line(self, writeofline):
        credit = 0.0
        debit = 0.0
        if writeofline.amount > 0.0:
            debit = abs(writeofline.amount)
        else:
            credit = abs(writeofline.amount)
        return {
            'name':
            writeofline.note,
            'credit':
            credit,
            'debit':
            debit,
            'account_id':
            writeofline.account_id.id,
            'partner_id':
            False,
            'currency_id':
            False,
            'amount_currency':
            False,
            'analytic_account_id':
            writeofline.analytic_id and writeofline.analytic_id.id or False,
        }
Esempio n. 2
0
class is_cout(models.Model):
    _name='is.cout'
    _order='name'
    _sql_constraints = [('name_uniq', 'unique(name)', u"Ce code existe déja !")]

    name                   = fields.Many2one('product.product', 'Article', required=True, readonly=False, select=True)
    code_pg                = fields.Char('Code PG'    , related='name.product_tmpl_id.is_code', readonly=True)
    designation            = fields.Char('Désignation', related='name.product_tmpl_id.name'   , readonly=True)
    cout_calcul_id         = fields.Many2one('is.cout.calcul', 'Calcul des coût')
    is_category_id         = fields.Many2one('is.category', 'Catégorie')
    is_gestionnaire_id     = fields.Many2one('is.gestionnaire', 'Gestionnaire')
    is_mold_id             = fields.Many2one('is.mold', 'Moule')
    is_mold_dossierf       = fields.Char('Moule ou Dossier F')
    partner_id             = fields.Many2one('res.partner', 'Client par défaut')
    type_article           = fields.Selection([('A', u'Acheté'),('F', u'Fabriqué'),('ST', u'Sous-traité')], "Type d'article")
    uom_id                 = fields.Many2one('product.uom', 'Unité')
    lot_mini               = fields.Float("Lot d'appro.")
    prix_tarif             = fields.Float("Prix tarif"                  , digits=(12, 4))
    prix_commande          = fields.Float("Prix dernière commande"      , digits=(12, 4))
    prix_facture           = fields.Float("Prix dernière facture"       , digits=(12, 4))
    prix_force             = fields.Float("Prix forcé (saisie manuelle)", digits=(12, 4))
    prix_force_commentaire = fields.Char("Commentaire")
    prix_calcule           = fields.Float("Prix calculé"                , digits=(12, 4))
    prix_sous_traitance    = fields.Float("Prix sous-traitance"         , digits=(12, 4))
    ecart_calcule_matiere  = fields.Float("Ecart Calculé/Matière"       , digits=(12, 4))

    cout_act_matiere       = fields.Float("Coût act matière"        , digits=(12, 4))
    cout_act_condition     = fields.Float("Coût act conditionnement", digits=(12, 4))
    cout_act_machine       = fields.Float("Coût act machine"        , digits=(12, 4))
    cout_act_mo            = fields.Float("Coût act main d'oeuvre"  , digits=(12, 4))
    cout_act_machine_pk    = fields.Float("Coût act machine PK"      , digits=(12, 4))
    cout_act_mo_pk         = fields.Float("Coût act main d'oeuvre PK", digits=(12, 4))
    cout_act_st            = fields.Float("Coût act sous-traitance" , digits=(12, 4))
    cout_act_total         = fields.Float("Coût act Total"          , digits=(12, 4))
    cout_act_prix_vente    = fields.Float("Prix de vente actualisé" , digits=(12, 4))

    cout_std_matiere       = fields.Float("Coût std matière"         , digits=(12, 4))
    cout_std_condition     = fields.Float("Coût std conditionnement" , digits=(12, 4))
    cout_std_machine       = fields.Float("Coût std machine"         , digits=(12, 4))
    cout_std_mo            = fields.Float("Coût std main d'oeuvre"   , digits=(12, 4))
    cout_std_st            = fields.Float("Coût std sous-traitance"  , digits=(12, 4))
    cout_std_total         = fields.Float("Coût std Total"           , digits=(12, 4))
    cout_std_prix_vente    = fields.Float("Prix de vente standard"   , digits=(12, 4))

    cout_budget_matiere       = fields.Float("Coût budget matière"         , digits=(12, 4))
    cout_budget_condition     = fields.Float("Coût budget conditionnement" , digits=(12, 4))
    cout_budget_machine       = fields.Float("Coût budget machine"         , digits=(12, 4))
    cout_budget_mo            = fields.Float("Coût budget main d'oeuvre"   , digits=(12, 4))
    cout_budget_st            = fields.Float("Coût budget sous-traitance"  , digits=(12, 4))
    cout_budget_total         = fields.Float("Coût budget Total"           , digits=(12, 4))
    cout_budget_prix_vente    = fields.Float("Prix de vente budget"        , digits=(12, 4))

    amortissement_moule    = fields.Float("Amortissement Moule"     , digits=(12, 4), compute='_compute')
    surcout_pre_serie      = fields.Float("Surcôut pré-série"       , digits=(12, 4), compute='_compute')
    prix_vente             = fields.Float("Prix de Vente"           , digits=(12, 4), compute='_compute')
    nomenclature_ids       = fields.One2many('is.cout.nomenclature', 'cout_id', u"Lignes de la nomenclature")
    gamme_ma_ids           = fields.One2many('is.cout.gamme.ma'    , 'cout_id', u"Lignes gamme machine")
    gamme_mo_ids           = fields.One2many('is.cout.gamme.mo'    , 'cout_id', u"Lignes gamme MO")
    gamme_ma_pk_ids        = fields.One2many('is.cout.gamme.ma.pk' , 'cout_id', u"Lignes gamme machine PK")
    gamme_mo_pk_ids        = fields.One2many('is.cout.gamme.mo.pk' , 'cout_id', u"Lignes gamme MO PK")
    niveau                 = fields.Integer('Niveau le plus bas dans la nomenclature')
    nb_err                 = fields.Integer('Nb Err', help=u"Nombre d'erreures détectées lors du calcul de coûts")


    @api.depends('name')
    def _compute(self):
        for obj in self:
            #** Recherche du tarif commercial pour le client par défaut ********
            code_client=mem_code_client=False
            for client in obj.name.product_tmpl_id.is_client_ids:
                mem_code_client=client.client_id.is_code
                if client.client_defaut:
                    code_client=mem_code_client
            if code_client==False:
                code_client=mem_code_client
            tarifs=self.env['is.tarif.cial'].search([
                ('product_id', '=', obj.name.product_tmpl_id.id),
                ('indice_prix', '=', 999),
                ('partner_id.is_code', '=', code_client)
            ])
            for tarif in tarifs:
                obj.amortissement_moule = tarif.amortissement_moule
                obj.surcout_pre_serie   = tarif.surcout_pre_serie
                obj.prix_vente          = tarif.prix_vente


    @api.multi
    def write(self, vals):
        for obj in self:
            matiere   = vals.get('cout_std_matiere'  , obj.cout_std_matiere)
            machine   = vals.get('cout_std_machine'  , obj.cout_std_machine)
            mo        = vals.get('cout_std_mo'       , obj.cout_std_mo)
            st        = vals.get('cout_std_st'       , obj.cout_std_st)
            vals['cout_std_total']=matiere+machine+mo+st
        res=super(is_cout, self).write(vals)
        return res


    @api.multi
    def action_calcul_cout(self):
        for obj in self:
            vals={
                'product_id'   : obj.name.id,
                'multiniveaux' : False,
            }
            cout_calcul=self.env['is.cout.calcul'].create(vals)
            cout_calcul.action_calcul_prix_achat_thread(nb_threads=0)
            cout_calcul.action_calcul_prix_revient()
            
            return {
                'name': obj.name.name,
                'view_mode': 'form',
                'view_type': 'form',
                'res_model': 'is.cout',
                'type': 'ir.actions.act_window',
                'res_id': obj.id,
            }


    @api.multi
    def action_calcul_cout_pk(self):
        for obj in self:
            vals={
                'product_id'   : obj.name.id,
                'multiniveaux' : False,
            }
            cout_calcul=self.env['is.cout.calcul'].create(vals)
            cout_calcul.action_calcul_prix_achat_thread(nb_threads=0)
            cout_calcul.action_calcul_prix_revient()
            dummy, view_id = self.env['ir.model.data'].get_object_reference('is_plastigray', 'is_cout_pk_form_view')
            return {
                'name': obj.name.name,
                'view_mode': 'form',
                'view_type': 'form',
                'res_model': 'is.cout',
                'type': 'ir.actions.act_window',
                'view_id': view_id,
                'res_id': obj.id,
            }


    @api.multi
    def _copie_cout_actualise_dans_cout_standard(self,obj):
        vals={
            'cout_std_matiere'    : obj.cout_act_matiere,
            'cout_std_condition'  : obj.cout_act_condition,
            'cout_std_machine'    : obj.cout_act_machine,
            'cout_std_mo'         : obj.cout_act_mo,
            'cout_std_st'         : obj.cout_act_st,
            'cout_std_total'      : obj.cout_act_total,
            'cout_std_prix_vente' : obj.cout_act_prix_vente,
        }
        obj.write(vals)


    @api.multi
    def copie_cout_actualise_dans_cout_standard(self):
        for obj in self:
            self._copie_cout_actualise_dans_cout_standard(obj)




    @api.multi
    def _copie_cout_actualise_dans_cout_budget(self,obj):
        vals={
            'cout_budget_matiere'    : obj.cout_act_matiere,
            'cout_budget_condition'  : obj.cout_act_condition,
            'cout_budget_machine'    : obj.cout_act_machine,
            'cout_budget_mo'         : obj.cout_act_mo,
            'cout_budget_st'         : obj.cout_act_st,
            'cout_budget_total'      : obj.cout_act_total,
            'cout_budget_prix_vente' : obj.cout_act_prix_vente,
        }
        obj.write(vals)


    @api.multi
    def copie_cout_actualise_dans_cout_budget(self):
        for obj in self:
            self._copie_cout_actualise_dans_cout_budget(obj)










    @api.multi
    def initialisation_prix_vente_standard(self):
        for obj in self:
            obj.cout_std_prix_vente = obj.prix_vente-obj.amortissement_moule-obj.surcout_pre_serie

    @api.model
    def print_btn_report(self):
        threaded_calculation = threading.Thread(target=self.save_cout_report, args=())
        threaded_calculation.start()
        return True

    def save_cout_report(self):
        user = self.env['res.users'].browse(self._uid)
        with api.Environment.manage():
            new_cr = self.pool.cursor()
            self = self.with_env(self.env(cr=new_cr))
            report_service = 'is_plastigray.report_is_cout'
            #file_param  = self.env['ir.config_parameter'].get_param('path_report_pdf')
            db=self._cr.dbname
            path="/tmp/couts-" + db
            cde="rm -Rf " + path
            os.popen(cde).readlines()
            if not os.path.exists(path):
                os.makedirs(path)
            recs=self.search([], order="name",limit=50000)
            nb=len(recs)
            _logger.info("#### Début sauvegarde Coûts ####")
            ct=0
            for rec in recs:
                ct=ct+1
                code_pg=rec.name.is_code
                _logger.info('- '+str(ct)+'/'+str(nb)+' : '+str(code_pg))
                result, format = self.env['report'].get_pdf(rec, report_service), 'pdf'
                file_name = path + '/'+str(code_pg) +'.pdf'
                fd = os.open(file_name,os.O_RDWR|os.O_CREAT)
                try:
                    os.write(fd, result)
                finally:
                    os.close(fd)
            filename="/var/www/odoo/couts/"+db+".zip"
            cde="rm -f " + filename + " && cd /tmp && zip -r " + filename + " couts-" +db+" && chmod 755 "+filename
            os.popen(cde).readlines()
            self.send_mail_notyfy_user()
            new_cr.close()
            _logger.info("#### Fin sauvegarde Coûts ####")
            return {}

    def send_mail_notyfy_user(self):
        db=self._cr.dbname
        user = self.env['res.users'].browse(self._uid)
        mail_pool = self.env['mail.mail']
        values={}
        values.update({'subject': 'Génération des PDF des coûts terminée'})
        values.update({'email_from': user.partner_id.email})
        values.update({'email_to': user.partner_id.email})
        values.update({'body_html': '<p>Bonjour,</p><p>Le zip contenant tous les PDF est disponible <a href="http://odoo/couts/'+db+'.zip">ici</a></p>' })
        #values.update({'body': 'Bonjour,\nLe zip contenant tous les PDF est disonible ici http://odoo/couts-odoo1.zip' })
#         values.update({'res_id': 'obj.id' }) #[optional] here is the record id, where you want to post that email after sending
        values.update({'model': 'is.cout' }) #[optional] here is the object(like 'project.project')  to whose record id you want to post that email after sending
        msg_id = mail_pool.sudo().create(values)
        # And then call send function of the mail.mail,
        if msg_id:
            msg_id.send()
        return True

    @api.multi
    def cout_standard_indice_precedent(self):
        if len(self)>1:
            raise Warning(u"Modification multiple non autorisée !")
        for obj in self:
            is_code=obj.name.is_code
            indice=is_code[6:7]
            if indice=='':
                raise Warning(u"Code sans indice !")
            code=is_code[0:6]
            if indice!='A':
                code=code+chr(ord(indice)-1)
            couts=self.env['is.cout'].search([('name.is_code', '=', code)])
            if len(couts)==0:
                raise Warning(u"Coût précédent non trouvé !")
            for cout in couts:
                obj.cout_std_matiere    = cout.cout_std_matiere
                obj.cout_std_condition  = cout.cout_std_condition
                obj.cout_std_machine    = cout.cout_std_machine
                obj.cout_std_mo         = cout.cout_std_mo
                obj.cout_std_st         = cout.cout_std_st
                obj.cout_std_total      = cout.cout_std_total
                obj.cout_std_prix_vente = cout.cout_std_prix_vente
Esempio n. 3
0
class res_partner(models.Model):

    _inherit = 'res.partner'

    # F#13145 In the tree view of partner,
    # replace the column Phone by "Phone/Mobile"

    @api.multi
    def _get_full_phone(self):
        for record in self:
            full_phone = []
            if record.phone:
                full_phone.append(record.phone)
            if record.mobile:
                full_phone.append(record.mobile)
            record.phone_mobile = " / ".join(full_phone) if full_phone else ''

    @api.depends('is_company')
    def _get_title_domain(self):
        """
        Use for the domain on field Title:
        - NOT Is Company: titles with type `contact`
        - Is Company: titles with type `partner`
        """
        for record in self:
            if record.is_company:
                record.title_domain = 'partner'
            else:
                record.title_domain = 'contact'

    phone_mobile = fields.Char(compute='_get_full_phone',
                               string='Phone/Mobile')

    event_ids = fields.One2many(comodel_name='trobz.crm.event',
                                inverse_name='partner_id',
                                string='Events')
    lead_ids = fields.One2many(comodel_name='crm.lead',
                               inverse_name='partner_id',
                               string='Leads')
    skype_contact = fields.Char('Skype Contact', size=64)
    linkedin_profile = fields.Char('Linkedin Profile', size=64)
    create_uid = fields.Many2one(comodel_name='res.users', string='Creator')
    create_date = fields.Datetime('Creation Date')
    prospect = fields.Boolean(
        'Prospect', help="Check this box if this contact is a prospect.")
    business_sector_id = fields.Many2one(
        comodel_name='trobz.crm.business.sector', string='Business Sector')
    title_domain = fields.Selection([('contact', 'Contact'),
                                     ('partner', 'Partner')],
                                    'Title Domain',
                                    compute='_get_title_domain',
                                    store=True)

    @api.onchange('customer')
    def check_cutomer(self):
        if self.customer:
            self.prospect = False

    @api.onchange('prospect')
    def check_prospect(self):
        if self.prospect:
            self.customer = False

    @api.onchange('parent_id')
    def onchange_parent_id(self):
        if self.parent_id:
            self.customer = self.parent_id.customer
            self.prospect = self.parent_id.prospect
            self.supplier = self.parent_id.supplier

    # Can not migrate this function because onchange_state is called from Odoo
    def onchange_state(self, cr, uid, ids, state_id, context=None):
        if state_id:
            country_id = self.pool.get('res.country.state').browse(
                cr, uid, state_id, context).country_id.id
            return {'value': {'country_id': country_id}}
        return {}

    @api.model
    def default_get(self, fields):
        ctx = self._context and self._context.copy() or {}
        res = super(res_partner, self).default_get(fields)
        res.update({
            'is_company': False,
        })

        # F#12640 : Update Related User and company for Partner.contact
        # Get customer/prospect/supplier like company
        if ctx.get('default_parent_id', False):
            parent_obj = self.browse(ctx['default_parent_id'])
            res.update({
                'customer': parent_obj.customer,
                'prospect': parent_obj.prospect,
                'supplier': parent_obj.supplier,
                'use_parent_address': True,
            })

        return res

    @api.multi
    def write(self, vals):
        context = self._context and self._context.copy() or {}
        context.update({'from_partner': 1})
        res = super(res_partner, self).write(vals)
        # F#12640: For partner set as is_company, when updating the fields
        # ‘Customer/Supplier/Prospect’, automatically set the same value
        # on the contacts of that company.
        child_new_vals = {}
        if 'customer' in vals:
            child_new_vals['customer'] = vals.get('customer', False)
        if 'prospect' in vals:
            child_new_vals['prospect'] = vals.get('prospect', False)
        if 'supplier' in vals:
            child_new_vals['supplier'] = vals.get('supplier', False)

        if child_new_vals:
            for parent_obj in self:
                if parent_obj.is_company and parent_obj.child_ids:
                    parent_obj.child_ids.write(child_new_vals)
        return res

    @api.multi
    def name_get(self):
        context = self._context or {}
        if not self:
            return []
        res = []
        for r in self:
            if context.get('contact_display', 'contact') == 'partner' and \
                    r.parent_id:
                res.append((r.id, r.parent_id.id))
            else:
                res.append((r.id, r.name or '/'))
        return res

    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        if not args:
            args = []
        context = dict(self._context)
        if 'crm_partner_id' in context:
            crm_partner_id = context.get('crm_partner_id', False)
            if not crm_partner_id:
                args = [('id', 'in', [])]
            else:
                partners = self.env['res.partner'].search([('id', '=',
                                                            crm_partner_id)])
                if partners:
                    partner = partners[0]
                    contact_ids = [contact.id for contact in partner.child_ids]
                    args = [('id', 'in', contact_ids)]

        return super(res_partner, self).name_search(name=name,
                                                    args=args,
                                                    operator=operator,
                                                    limit=limit)
Esempio n. 4
0
File: sale.py Progetto: eksotama/OCB
class SaleOrderLine(models.Model):
    _name = 'sale.order.line'
    _description = 'Sales Order Line'
    _order = 'order_id desc, sequence, id'

    @api.depends('state', 'product_uom_qty', 'qty_delivered', 'qty_to_invoice',
                 'qty_invoiced')
    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'

    @api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id')
    def _compute_amount(self):
        """
        Compute the amounts of the SO line.
        """
        for line in self:
            price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
            taxes = line.tax_id.compute_all(price,
                                            line.order_id.currency_id,
                                            line.product_uom_qty,
                                            product=line.product_id,
                                            partner=line.order_id.partner_id)
            line.update({
                'price_tax':
                taxes['total_included'] - taxes['total_excluded'],
                'price_total':
                taxes['total_included'],
                'price_subtotal':
                taxes['total_excluded'],
            })

    @api.depends('product_id.invoice_policy', 'order_id.state')
    def _compute_qty_delivered_updateable(self):
        for line in self:
            line.qty_delivered_updateable = line.product_id.invoice_policy in (
                'order', 'delivery'
            ) and line.order_id.state == 'sale' and line.product_id.track_service == 'manual'

    @api.depends('qty_invoiced', 'qty_delivered', 'product_uom_qty',
                 'order_id.state')
    def _get_to_invoice_qty(self):
        """
        Compute the quantity to invoice. If the invoice policy is order, the quantity to invoice is
        calculated from the ordered quantity. Otherwise, the quantity delivered is used.
        """
        for line in self:
            if line.order_id.state in ['sale', 'done']:
                if line.product_id.invoice_policy == 'order':
                    line.qty_to_invoice = line.product_uom_qty - line.qty_invoiced
                else:
                    line.qty_to_invoice = line.qty_delivered - line.qty_invoiced
            else:
                line.qty_to_invoice = 0

    @api.depends('invoice_lines.invoice_id.state', 'invoice_lines.quantity')
    def _get_invoice_qty(self):
        """
        Compute the quantity invoiced. If case of a refund, the quantity invoiced is decreased. Note
        that this is the case only if the refund is generated from the SO and that is intentional: if
        a refund made would automatically decrease the invoiced quantity, then there is a risk of reinvoicing
        it automatically, which may not be wanted at all. That's why the refund has to be created from the SO
        """
        for line in self:
            qty_invoiced = 0.0
            for invoice_line in line.invoice_lines:
                if invoice_line.invoice_id.state != 'cancel':
                    if invoice_line.invoice_id.type == 'out_invoice':
                        qty_invoiced += invoice_line.quantity
                    elif invoice_line.invoice_id.type == 'out_refund':
                        qty_invoiced -= invoice_line.quantity
            line.qty_invoiced = qty_invoiced

    @api.depends('price_subtotal', 'product_uom_qty')
    def _get_price_reduce(self):
        for line in self:
            line.price_reduce = line.price_subtotal / line.product_uom_qty if line.product_uom_qty else 0.0

    @api.multi
    def _compute_tax_id(self):
        for line in self:
            fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id
            if fpos:
                # The superuser is used by website_sale in order to create a sale order. We need to make
                # sure we only select the taxes related to the company of the partner. This should only
                # apply if the partner is linked to a company.
                if self.env.uid == SUPERUSER_ID and line.order_id.company_id:
                    taxes = fpos.map_tax(line.product_id.taxes_id).filtered(
                        lambda r: r.company_id == line.order_id.company_id)
                else:
                    taxes = fpos.map_tax(line.product_id.taxes_id)
                line.tax_id = taxes
            else:
                line.tax_id = line.product_id.taxes_id if line.product_id.taxes_id else False

    @api.multi
    def _prepare_order_line_procurement(self, group_id=False):
        self.ensure_one()
        return {
            'name':
            self.name,
            'origin':
            self.order_id.name,
            'date_planned':
            datetime.strptime(self.order_id.date_order,
                              DEFAULT_SERVER_DATETIME_FORMAT) +
            timedelta(days=self.customer_lead),
            'product_id':
            self.product_id.id,
            'product_qty':
            self.product_uom_qty,
            'product_uom':
            self.product_uom.id,
            'company_id':
            self.order_id.company_id.id,
            'group_id':
            group_id,
            'sale_line_id':
            self.id
        }

    @api.multi
    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:
                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

    @api.model
    def _get_analytic_invoice_policy(self):
        return ['cost']

    @api.model
    def _get_analytic_track_service(self):
        return []

    @api.model
    def create(self, values):
        line = super(SaleOrderLine, self).create(values)
        if line.state == 'sale':
            if line.product_id.track_service in self._get_analytic_track_service(
            ) or line.product_id.invoice_policy in self._get_analytic_invoice_policy(
            ) and not line.order_id.project_id:
                line.order_id._create_analytic_account()
            line._action_procurement_create()

        return line

    @api.multi
    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

    order_id = fields.Many2one('sale.order',
                               string='Order Reference',
                               required=True,
                               ondelete='cascade',
                               index=True,
                               copy=False)
    name = fields.Text(string='Description', required=True)
    sequence = fields.Integer(string='Sequence', default=10)

    invoice_lines = fields.Many2many('account.invoice.line',
                                     'sale_order_line_invoice_rel',
                                     'order_line_id',
                                     'invoice_line_id',
                                     string='Invoice Lines',
                                     copy=False)
    invoice_status = fields.Selection([('upselling', 'Upselling Opportunity'),
                                       ('invoiced', 'Fully Invoiced'),
                                       ('to invoice', 'To Invoice'),
                                       ('no', 'Nothing to Invoice')],
                                      string='Invoice Status',
                                      compute='_compute_invoice_status',
                                      store=True,
                                      readonly=True,
                                      default='no')
    price_unit = fields.Float('Unit Price',
                              required=True,
                              digits=dp.get_precision('Product Price'),
                              default=0.0)

    price_subtotal = fields.Monetary(compute='_compute_amount',
                                     string='Subtotal',
                                     readonly=True,
                                     store=True)
    price_tax = fields.Monetary(compute='_compute_amount',
                                string='Taxes',
                                readonly=True,
                                store=True)
    price_total = fields.Monetary(compute='_compute_amount',
                                  string='Total',
                                  readonly=True,
                                  store=True)

    price_reduce = fields.Monetary(compute='_get_price_reduce',
                                   string='Price Reduce',
                                   readonly=True,
                                   store=True)
    tax_id = fields.Many2many('account.tax', string='Taxes')

    discount = fields.Float(string='Discount (%)',
                            digits=dp.get_precision('Discount'),
                            default=0.0)

    product_id = fields.Many2one('product.product',
                                 string='Product',
                                 domain=[('sale_ok', '=', True)],
                                 change_default=True,
                                 ondelete='restrict',
                                 required=True)
    product_uom_qty = fields.Float(
        string='Quantity',
        digits=dp.get_precision('Product Unit of Measure'),
        required=True,
        default=1.0)
    product_uom = fields.Many2one('product.uom',
                                  string='Unit of Measure',
                                  required=True)

    qty_delivered_updateable = fields.Boolean(
        compute='_compute_qty_delivered_updateable',
        string='Can Edit Delivered',
        readonly=True,
        default=True)
    qty_delivered = fields.Float(
        string='Delivered',
        copy=False,
        digits=dp.get_precision('Product Unit of Measure'),
        default=0.0)
    qty_to_invoice = fields.Float(
        compute='_get_to_invoice_qty',
        string='To Invoice',
        store=True,
        readonly=True,
        digits=dp.get_precision('Product Unit of Measure'),
        default=0.0)
    qty_invoiced = fields.Float(
        compute='_get_invoice_qty',
        string='Invoiced',
        store=True,
        readonly=True,
        digits=dp.get_precision('Product Unit of Measure'),
        default=0.0)

    salesman_id = fields.Many2one(related='order_id.user_id',
                                  store=True,
                                  string='Salesperson',
                                  readonly=True)
    currency_id = fields.Many2one(related='order_id.currency_id',
                                  store=True,
                                  string='Currency',
                                  readonly=True)
    company_id = fields.Many2one(related='order_id.company_id',
                                 string='Company',
                                 store=True,
                                 readonly=True)
    order_partner_id = fields.Many2one(related='order_id.partner_id',
                                       store=True,
                                       string='Customer')

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('sale', 'Sale Order'),
        ('done', 'Done'),
        ('cancel', 'Cancelled'),
    ],
                             related='order_id.state',
                             string='Order Status',
                             readonly=True,
                             copy=False,
                             store=True,
                             default='draft')

    customer_lead = fields.Float(
        'Delivery Lead Time',
        required=True,
        default=0.0,
        help=
        "Number of days between the order confirmation and the shipping of the products to the customer",
        oldname="delay")
    procurement_ids = fields.One2many('procurement.order',
                                      'sale_line_id',
                                      string='Procurements')

    @api.multi
    def _prepare_invoice_line(self, qty):
        """
        Prepare the dict of values to create the new invoice line for a sales order line.

        :param qty: float quantity to invoice
        """
        self.ensure_one()
        res = {}
        account = self.product_id.property_account_income_id or self.product_id.categ_id.property_account_income_categ_id
        if not account:
            raise UserError(_('Please define income account for this product: "%s" (id:%d) - or for its category: "%s".') % \
                            (self.product_id.name, self.product_id.id, self.product_id.categ_id.name))

        fpos = self.order_id.fiscal_position_id or self.order_id.partner_id.property_account_position_id
        if fpos:
            account = fpos.map_account(account)

        res = {
            'name': self.name,
            'sequence': self.sequence,
            'origin': self.order_id.name,
            'account_id': account.id,
            'price_unit': self.price_unit,
            'quantity': qty,
            'discount': self.discount,
            'uom_id': self.product_uom.id,
            'product_id': self.product_id.id or False,
            'invoice_line_tax_ids': [(6, 0, self.tax_id.ids)],
            'account_analytic_id': self.order_id.project_id.id,
        }
        return res

    @api.multi
    def invoice_line_create(self, invoice_id, qty):
        """
        Create an invoice line. The quantity to invoice can be positive (invoice) or negative
        (refund).

        :param invoice_id: integer
        :param qty: float quantity to invoice
        """
        precision = self.env['decimal.precision'].precision_get(
            'Product Unit of Measure')
        for line in self:
            if not float_is_zero(qty, precision_digits=precision):
                vals = line._prepare_invoice_line(qty=qty)
                vals.update({
                    'invoice_id': invoice_id,
                    'sale_line_ids': [(6, 0, [line.id])]
                })
                self.env['account.invoice.line'].create(vals)

    @api.multi
    @api.onchange('product_id')
    def product_id_change(self):
        if not self.product_id:
            return {'domain': {'product_uom': []}}

        vals = {}
        domain = {
            'product_uom':
            [('category_id', '=', self.product_id.uom_id.category_id.id)]
        }
        if not (self.product_uom and (self.product_id.uom_id.category_id.id
                                      == self.product_uom.category_id.id)):
            vals['product_uom'] = self.product_id.uom_id

        product = self.product_id.with_context(
            lang=self.order_id.partner_id.lang,
            partner=self.order_id.partner_id.id,
            quantity=self.product_uom_qty,
            date=self.order_id.date_order,
            pricelist=self.order_id.pricelist_id.id,
            uom=self.product_uom.id)

        name = product.name_get()[0][1]
        if product.description_sale:
            name += '\n' + product.description_sale
        vals['name'] = name

        self._compute_tax_id()

        if self.order_id.pricelist_id and self.order_id.partner_id:
            vals['price_unit'] = self.env[
                'account.tax']._fix_tax_included_price(product.price,
                                                       product.taxes_id,
                                                       self.tax_id)
        self.update(vals)
        return {'domain': domain}

    @api.onchange('product_uom', 'product_uom_qty')
    def product_uom_change(self):
        if not self.product_uom:
            self.price_unit = 0.0
            return
        if self.order_id.pricelist_id and self.order_id.partner_id:
            product = self.product_id.with_context(
                lang=self.order_id.partner_id.lang,
                partner=self.order_id.partner_id.id,
                quantity=self.product_uom_qty,
                date_order=self.order_id.date_order,
                pricelist=self.order_id.pricelist_id.id,
                uom=self.product_uom.id)
            self.price_unit = self.env['account.tax']._fix_tax_included_price(
                product.price, product.taxes_id, self.tax_id)

    @api.multi
    def unlink(self):
        if self.filtered(lambda x: x.state in ('sale', 'done')):
            raise UserError(
                _('You can not remove a sale order line.\nDiscard changes and try setting the quantity to 0.'
                  ))
        return super(SaleOrderLine, self).unlink()

    @api.multi
    def _get_delivered_qty(self):
        '''
        Intended to be overridden in sale_stock and sale_mrp
        :return: the quantity delivered
        :rtype: float
        '''
        return 0.0
class MedicalPrescriptionOrder(models.Model):
    _name = 'medical.prescription.order'
    _description = 'Medical Prescription Order'

    notes = fields.Text()
    name = fields.Char(
        required=True,
        default=lambda s: s._default_name()
    )
    patient_id = fields.Many2one(
        string='Patient',
        comodel_name='medical.patient',
        required=True,
        help='Primary patient this is regarding',
    )
    physician_id = fields.Many2one(
        string='Physician',
        comodel_name='medical.physician',
        required=True,
        help='Physician that issued prescription',
    )
    partner_id = fields.Many2one(
        string='Pharmacy',
        comodel_name='medical.pharmacy',
    )
    prescription_order_line_ids = fields.One2many(
        string='Prescription Order Lines',
        comodel_name='medical.prescription.order.line',
        inverse_name='prescription_order_id',
    )
    is_pregnancy_warning = fields.Boolean(
        string='Pregnant',
        help='Check this if the primary patient on prescription is pregnant',
    )
    is_verified = fields.Boolean(
        string='Verified',
        help='Check this if the prescription has been confirmed as valid',
    )
    date_prescription = fields.Datetime(
        string='Prescription Date',
        default=lambda s: fields.Datetime.now(),
    )
    active = fields.Boolean(
        compute='_compute_active',
        store=True,
    )

    @api.model
    def _default_name(self):
        return self.env['ir.sequence'].next_by_code(
            'medical.prescription.order',
        )

    @api.multi
    @api.depends('prescription_order_line_ids',
                 'prescription_order_line_ids.active',
                 )
    def _compute_active(self):
        for rec_id in self:
            if not rec_id.prescription_order_line_ids:
                rec_id.active = True
                continue
            rec_id.active = any(
                rec_id.prescription_order_line_ids.mapped('active')
            )
Esempio n. 6
0
class realizar_pago_wizard(models.TransientModel):
    _name = "realizar.pago.wizard"

    @api.model
    def default_get(self, fields_list):
        origen = self.env['encargo.encargo'].search([
            ('id', 'in', self.env.context.get('active_ids', []))
        ])
        res = models.TransientModel.default_get(self, fields_list)
        ids = self.env.context.get('active_ids', [])
        pagos = self.env['pagos.encargo.line'].browse(ids)
        wizard_obj = self.env['realizar.pago.wizard.lines']
        ds = []
        debe = 0
        for pago in origen.pagos_line:
            if pago.state == 'draft':
                d = wizard_obj.create({
                    'wizard_id': self.id,
                    'fecha': pago.fecha,
                    'importe': pago.importe,
                    'pago_line_id': pago.id,
                })
                ds.append(d.id)
                debe += pago.importe

        res['cliente_id'] = origen.cliente_id.id
        res['importe_pendiente'] = debe
        res['pagos_line'] = ds

        return res

    def pagar(self, cr, uid, ids, context=None):
        for e in self.browse(cr, uid, ids, context=None):
            wizard_line_obj = self.pool.get('realizar.pago.wizard.lines')
            trabajo_obj = self.pool.get('trabajo.trabajo')

            wizard_ids = wizard_line_obj.search(
                cr, uid, [('select', '=', True),
                          ('wizard_id', '=', e.encargo_origen_id.id)])
            if not wizard_ids:
                raise osv.except_osv(
                    _('Error!'), _("Seleccione al menos un pago a realizar."))

            if wizard_ids:
                pagos_line_obj = self.pool.get('pagos.encargo.line')
                for w in wizard_ids:
                    wid = wizard_line_obj.browse(cr, uid, w, context=context)
                    pagos_line_obj.write(cr, uid, wid.pago_line_id.id,
                                         {'state': 'done'})
                    #crear un trabajo
                    # trabajo_obj = self.pool.get('trabajo.trabajo')
                    # predef_ob = self.pool.get('predefinida.predefinida')
                    # predef_id = predef_ob.search(cr, uid, [('name','=','Pago parcial trabajo por encargo')])
                    # total = wid.importe
                    # cliente_id = e.encargo_origen_id.cliente_id.id
                    # vals = {
                    #     'costo': total,
                    #     'cliente': cliente_id,
                    #     'name': predef_id[0],
                    #     }
                    # nid = trabajo_obj.create(cr, uid, vals)

        # #eliminar los transientModels creados
        # wizard_obj = self.pool.get('realizar.pago.wizard')
        # wizard_ids = wizard_obj.search(cr, uid, [])
        # for w in wizard_ids:
        #     wizard = wizard_obj.browse(cr, uid, w)
        #     wizard.unlink()

        return True

    encargo_origen_id = fields.Many2one(
        'encargo.encargo',
        'Encargo',
        help="Encargo al que pertenecen los pagos a realizar.")
    cliente_id = fields.Many2one('cliente.cliente', 'Cliente')
    fecha = fields.Date(
        'Fecha',
        help=
        "Fecha en la que se realiza el pago. No necesariamente tiene que coincidir con las fechas indicadas en la linea de pagos pendientes. Al realizar el pago, se registrara un trabajo cuya fecha coincide con la especificada en este campo."
    )
    importe_pendiente = fields.Float('Importe pendiente (MN)')
    pagos_line = fields.One2many('realizar.pago.wizard.lines', 'wizard_id',
                                 'Pagos line')

    _defaults = {
        'fecha': fields.Date.today,
    }
Esempio n. 7
0
class settlement(models.Model):
    """Settlement model"""

    _name = "settlement"

    name = fields.Char(string="Settlement period",
                       required=True,
                       readonly=True)

    total = fields.Float(string="Total", readonly=True)

    date_from = fields.Date(string="From")

    date_to = fields.Date(string="To")

    settlement_agent_id = fields.One2many("settlement.agent",
                                          "settlement_id",
                                          string="Settlement agents",
                                          readonly=True)

    date = fields.Datetime(string="Created Date",
                           required=True,
                           default=fields.Datetime.now())

    # TODO: Workflow is necessary to manage 'cancel' state/transition
    state = fields.Selection([("invoiced", "Invoiced"), ("settled", "Settled"),
                              ("cancel", "Cancel")],
                             string="State",
                             readonly=True,
                             default="settled")

    def action_invoice_create(self,
                              cursor,
                              user,
                              ids,
                              journal_id,
                              product_id,
                              context=None):
        agents_pool = self.pool.get('settlement.agent')
        res = {}
        for settlement in self.browse(cursor, user, ids, context=context):
            settlement_agent_ids = map(lambda x: x.id,
                                       settlement.settlement_agent_id)
            invoices_agent = agents_pool.action_invoice_create(
                cursor,
                user,
                settlement_agent_ids,
                journal_id,
                product_id,
                context=context)
            res[settlement.id] = invoices_agent.values()
        return res

    def calculate(self,
                  cr,
                  uid,
                  ids,
                  agent_ids,
                  date_from,
                  date_to,
                  context=None):
        """generate one settlement line per agent"""
        # Search for all settlements in a period
        sale_agent_pool = self.pool['sale.agent']
        settlement_agent_pool = self.pool['settlement.agent']
        agents = sale_agent_pool.browse(cr, uid, agent_ids, context=context)
        total = 0
        for agent in agents:
            # generate one settlement line per agent
            liq_agent_id = settlement_agent_pool.create(
                cr,
                uid, {
                    'agent_id': agent.id,
                    'settlement_id': ids
                },
                context=context)
            settlement_agent_pool.calculate(cr,
                                            uid,
                                            liq_agent_id,
                                            date_from,
                                            date_to,
                                            context=context)
            liq_agent = settlement_agent_pool.browse(cr,
                                                     uid,
                                                     liq_agent_id,
                                                     context=context)
            total = total + liq_agent.total
        return self.write(cr, uid, ids, {'total': total}, context=context)

    def action_cancel(self, cr, uid, ids, context=None):
        """Cancel the liquidation"""
        agent_pool = self.pool['invoice.line.agent']
        for settle in self.browse(cr, uid, ids, context=context):
            for settle_line in settle.settlement_agent_id:
                for line in settle_line.lines:
                    line_id = line.invoice_line_id
                    commissions = [x.id for x in line_id.commission_ids]
                    commission_ids = line.invoice_line_id and commissions or []
                    if commission_ids:
                        agent_pool.write(cr,
                                         uid,
                                         commission_ids, {
                                             'settled': False,
                                             'quantity': 0.0
                                         },
                                         context=context)
        return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)

    def unlink(self, cr, uid, ids, context=None):
        """Allow to delete cancelled settlements"""
        for settle in self.browse(cr, uid, ids, context=context):
            if settle.state != 'cancel':
                raise exceptions.Warning(
                    _("You can't delete it, if it isn't in cancel state."))
        return super(settlement, self).unlink(cr, uid, ids, context=context)
Esempio n. 8
0
class EnrollmentResponse(models.Model):
    _name = "hc.res.enrollment.response"
    _description = "Enrollment Response"

    identifier_ids = fields.One2many(
        comodel_name="hc.enrollment.response.identifier",
        inverse_name="enrollment_response_id",
        string="Identifiers",
        help="Business Identifier.")
    status_id = fields.Many2one(comodel_name="hc.vs.fm.status",
                                string="Status",
                                help="The status of the resource instance.")
    status_history_ids = fields.One2many(
        comodel_name="hc.enrollment.response.status.history",
        inverse_name="enrollment_response_id",
        string="Status History",
        help="The status of the enrollment response over time.")
    request_id = fields.Many2one(comodel_name="hc.res.enrollment.request",
                                 string="Request",
                                 help="Claim reference.")
    outcome = fields.Selection(string="Enrollment Response Outcome",
                               selection=[("complete", "Complete"),
                                          ("error", "Error")],
                               help="Transaction status: error, complete.")
    disposition = fields.Text(string="Disposition",
                              help="Disposition Message.")
    ruleset_id = fields.Many2one(comodel_name="hc.vs.ruleset",
                                 string="Ruleset",
                                 help="Resource version.")
    original_ruleset_id = fields.Many2one(comodel_name="hc.vs.ruleset",
                                          string="Original Ruleset",
                                          help="Original version.")
    created = fields.Datetime(string="Creation Date", help="Creation date.")
    organization_id = fields.Many2one(comodel_name="hc.res.organization",
                                      string="Organization",
                                      help="Insurer.")
    request_provider_id = fields.Many2one(comodel_name="hc.res.practitioner",
                                          string="Request Provider",
                                          help="Responsible practitioner.")
    request_organization_id = fields.Many2one(
        comodel_name="hc.res.organization",
        string="Request Organization",
        help="Responsible organization.")

    @api.model
    def create(self, vals):
        status_history_obj = self.env['hc.enrollment.response.status.history']
        res = super(EnrollmentResponse, self).create(vals)
        if vals and vals.get('status_id'):
            status_history_vals = {
                'enrollment_response_id': res.id,
                'status': res.status_id.name,
                'start_date': datetime.today()
            }
            if vals.get('status_id') == 'entered-in-error':
                status_history_vals.update({'end_date': datetime.today()})
            status_history_obj.create(status_history_vals)
        return res

    @api.multi
    def write(self, vals):
        status_history_obj = self.env['hc.enrollment.response.status.history']
        fm_status_obj = self.env['hc.vs.fm.status']
        res = super(EnrollmentResponse, self).write(vals)
        status_history_record_ids = status_history_obj.search([('end_date',
                                                                '=', False)])
        if status_history_record_ids:
            if vals.get('status_id') and status_history_record_ids[
                    0].status != vals.get('status_id'):
                for status_history in status_history_record_ids:
                    status_history.end_date = datetime.strftime(
                        datetime.today(), DTF)
                    time_diff = datetime.today() - datetime.strptime(
                        status_history.start_date, DTF)
                    if time_diff:
                        days = str(time_diff).split(',')
                        if days and len(days) > 1:
                            status_history.time_diff_day = str(days[0])
                            times = str(days[1]).split(':')
                            if times and times > 1:
                                status_history.time_diff_hour = str(times[0])
                                status_history.time_diff_min = str(times[1])
                                status_history.time_diff_sec = str(times[2])
                        else:
                            times = str(time_diff).split(':')
                            if times and times > 1:
                                status_history.time_diff_hour = str(times[0])
                                status_history.time_diff_min = str(times[1])
                                status_history.time_diff_sec = str(times[2])
                fm_status = fm_status_obj.browse(vals.get('status_id'))
                status_history_vals = {
                    'enrollment_response_id': self.id,
                    'status': fm_status.name,
                    'start_date': datetime.today()
                }
                if vals.get('status_id') == 'entered-in-error':
                    status_id_history_vals.update(
                        {'end_date': datetime.today()})
                status_history_obj.create(status_history_vals)
        return res
Esempio n. 9
0
class ShiftTicket(models.Model):
    _inherit = 'event.event.ticket'
    _name = 'shift.ticket'
    _description = 'Shift Ticket'

    SHIFT_TYPE_SELECTION = [
        ('standard', 'Standard'),
        ('ftop', 'FTOP'),
    ]

    shift_type = fields.Selection(selection=SHIFT_TYPE_SELECTION,
                                  string='Shift type',
                                  compute='compute_shift_type',
                                  store=True)

    name = fields.Char(translate=False)
    shift_id = fields.Many2one('shift.shift',
                               "Shift",
                               required=True,
                               ondelete='cascade')
    event_id = fields.Many2one(required=False)
    product_id = fields.Many2one(
        default=lambda self: self._default_product_id(),
        domain=[("shift_type_id", "!=", False)],
    )
    registration_ids = fields.One2many('shift.registration', 'shift_ticket_id',
                                       'Registrations')
    date_begin = fields.Datetime(related="shift_id.date_begin")
    begin_date_string = fields.Char(
        string='Begin Date',
        compute='_compute_begin_date_fields',
        store=True,
    )
    user_id = fields.Many2one('res.partner',
                              related="shift_id.user_id",
                              store=True)

    @api.multi
    @api.depends('date_begin')
    def _compute_begin_date_fields(self):
        for ticket in self:
            ticket.begin_date_string = ticket.date_begin and datetime.strftime(
                datetime.strptime(ticket.date_begin, "%Y-%m-%d %H:%M:%S") +
                timedelta(hours=2), "%d/%m/%Y %H:%M:%S") or False

    @api.model
    def _default_product_id(self):
        try:
            product = self.env['ir.model.data'].get_object(
                'coop_shift', 'product_product_event')
            return product.id
        except ValueError:
            return False

    seats_availability = fields.Selection(compute='_compute_seats')
    seats_reserved = fields.Integer(compute='_compute_seats')
    seats_available = fields.Integer(compute='_compute_seats')
    seats_unconfirmed = fields.Integer(compute='_compute_seats')
    seats_used = fields.Integer(compute='_compute_seats', )

    @api.depends('product_id')
    @api.multi
    def compute_shift_type(self):
        for ticket in self:
            if ticket.product_id.id ==\
                    self.env.ref("coop_shift.product_product_shift_ftop").id:
                ticket.shift_type = 'ftop'
            else:
                ticket.shift_type = 'standard'

    @api.multi
    @api.depends('seats_max', 'registration_ids.state')
    def _compute_seats(self):
        """ Determine reserved, available, reserved but unconfirmed and used
            seats. """
        # initialize fields to 0 + compute seats availability
        for ticket in self:
            ticket.seats_availability = 'unlimited' if ticket.seats_max == 0\
                else 'limited'
            ticket.seats_unconfirmed = ticket.seats_reserved =\
                ticket.seats_used = ticket.seats_available = 0
        # aggregate registrations by ticket and by state
        if self.ids:
            state_field = {
                'draft': 'seats_unconfirmed',
                'open': 'seats_reserved',
                'done': 'seats_used',
            }
            query = """ SELECT shift_ticket_id, state, count(shift_id)
                        FROM shift_registration
                        WHERE shift_ticket_id IN %s
                        AND state IN ('draft', 'open', 'done')
                        GROUP BY shift_ticket_id, state
                    """
            self._cr.execute(query, (tuple(self.ids), ))
            for shift_ticket_id, state, num in self._cr.fetchall():
                ticket = self.browse(shift_ticket_id)
                ticket[state_field[state]] += num
        # compute seats_available
        for ticket in self:
            if ticket.seats_max > 0:
                ticket.seats_available = ticket.seats_max - (
                    ticket.seats_reserved + ticket.seats_used)

    @api.multi
    @api.constrains('registration_ids', 'seats_max')
    def _check_seats_limit(self):
        for ticket in self:
            if ticket.seats_max and ticket.seats_available < 0:
                raise UserError(_('No more available seats for the ticket'))

    @api.onchange('product_id')
    def onchange_product_id(self):
        price = self.product_id.list_price if self.product_id else 0
        return {'value': {'price': price}}
Esempio n. 10
0
class HrLoan(models.Model):
    _name = 'hr.loan'

    @api.one
    @api.constrains('requested_amount')
    def _requested_so(self):
        # if self.requested_amount and self.remaining_budget:
        #     if self.requested_amount < 0:
        #         raise UserError(_('The Requested Amount Must Be Larger Than Zero.'))
        #     if self.requested_amount > self.remaining_budget:
        #         raise UserError(_('The Requested Amount Must Be Larger Or Equal Than Remaining Budget.'))
        if not self.requested_amount:
            raise UserError(_('The Requested Amount Is Required.'))

        # elif not self.remaining_budget:
        #     raise UserError(_('The Remaining Budget IS Required.'))

        return True

    @api.multi
    def unlink(self):
        if self.state != 'draft':
            raise ValidationError(
                _('Error ! You Cannot Delete The Loan Tn This State '))
        else:
            for line in self.loan_line:
                if line.state == 'unpaid':
                    line.unlink()
                else:
                    raise ValidationError(
                        _('Error ! You Have Line Piad You Cannot Delete The Loan .'
                          ))
        return super(HrLoan, self).unlink()

    # @api.one
    # @api.depends('employee_id')
    # def compute_remaining_budget(self):
    #     remaining_budget = 0
    #     loan_line_obj = self.env['hr.loan.line']
    #     if self.employee_id:
    #
    #         total_unpaid_amount = 0
    #         loan_line_data = loan_line_obj.search(
    #             [('loan_id.employee_id', '=', self.employee_id.id), ('state', 'in', ('unpaid', 'partial_paid'))])
    #         for loan_line in loan_line_data:
    #             total_unpaid_amount += loan_line.amount - loan_line.paid_amount
    #
    #         contract_id = False
    #         if self.employee_id.contract_id:
    #             contract_id = self.employee_id.contract_id
    #
    #         if contract_id:
    #             total_loan_budget = contract_id.total_loan_budget
    #             if total_unpaid_amount <= total_loan_budget:
    #                 remaining_budget = total_loan_budget - total_unpaid_amount
    #             else:
    #                 remaining_budget = 0
    #
    #     self.remaining_budget = remaining_budget
    #     return True

    name = fields.Char(required=True)

    # remaining_budget = fields.Float(string="Total Loan Budget", compute=compute_remaining_budget, store=True,
    #                                 required=False, )

    employee_id = fields.Many2one('hr.employee',
                                  string='Employee',
                                  required=True)
    company_id = fields.Many2one(related='employee_id.company_id',
                                 string='Company',
                                 readonly=True,
                                 store=True)
    requested_date = fields.Date(default=fields.Date.today())
    settlement_date = fields.Date(string='Start Date For Settlement',
                                  default=fields.Date.today())
    requested_amount = fields.Float(required=True)
    installment_amount = fields.Float(required=True)
    # installment = fields.Integer(string='Installment (months)', default=1, required=True)
    state = fields.Selection([('draft', 'Draft'), ('cancel', 'Cancelled'),
                              ('approved', 'Approved'), ('sent', 'Sent'),
                              ('closed', 'Closed')],
                             default='draft',
                             readonly=True,
                             copy=False,
                             track_visibility='onchange')

    loan_line = fields.One2many('hr.loan.line', 'loan_id')
    journal_created = fields.Boolean(default=False)

    @api.one
    def action_approved(self):
        """ Put the state of the Loan into approved state """
        if self.loan_line:
            requested_amount = self.requested_amount

            total_amount = sum((one_line.amount - one_line.paid_amount)
                               for one_line in self.loan_line)
            if total_amount != requested_amount:
                raise ValidationError(
                    _('Error ! Total Amount In lines Must Be Equal The Requested Amount.'
                      ))
            self.write({'state': 'approved'})
        else:
            raise ValidationError(
                _('Error ! You Cannot Approved Without Lines .'))
        return True

    @api.one
    def action_cancel(self):
        """ Put the state of the Loan into cancel state """
        if self.state == 'draft':
            self.write({'state': 'cancel'})
        else:
            raise ValidationError(
                _('Error ! You Cannot Cancel Loan In Approved State .'))
        return True

    @api.multi
    @api.depends('settlement_date', 'requested_amount', 'installment_amount')
    def action_populate(self):
        if self.installment_amount:
            loan_line = self.env['hr.loan.line']
            if self.loan_line:
                for line in self.loan_line:
                    line.unlink()
            # if len(self.loan_line) > 0:
            #     raise UserError(_('Not allowed to populate more than one time'))
            requested_amount = self.requested_amount

            amount = self.installment_amount
            installment = int(math.floor(self.requested_amount / amount))
            tagme3a = round(amount, 2) * float(installment)
            diff_nesba = 0
            if requested_amount != tagme3a:
                diff_nesba = requested_amount - tagme3a
            if diff_nesba < 0:
                raise ValidationError(
                    _('Total of installments is greater than the requested amount'
                      ))

            date_start_dt = fields.Datetime.from_string(self.settlement_date)
            for i in range(installment):
                # add_diff = 0.0
                # if i == 0:
                #     add_diff = diff_nesba
                loan_line.create({
                    'amount': round(amount, 2),
                    'date': date_start_dt.date(),
                    'loan_id': self.id,
                    'state': 'unpaid'
                })
                date_start_dt = (date_start_dt + relativedelta(months=+1))
            if diff_nesba > 0:
                loan_line.create({
                    'amount': diff_nesba,
                    'date': date_start_dt.date(),
                    'loan_id': self.id,
                    'state': 'unpaid'
                })
        else:
            raise ValidationError(
                _('Error ! Number Of Months Must Be Larger Than Zero .'))
        return True

    @api.multi
    def send_payment_request(self):
        if self.employee_id.address_home_id:
            if self.employee_id.address_home_id.customer == True:
                request_date = fields.Date.today()
                vals = {
                    # 'name': self.env['ir.sequence'].next_by_code('loan.payment'),
                    'desc':
                    self.name,
                    'req_amount':
                    self.requested_amount,
                    'req_date':
                    request_date,
                    'employee_id':
                    self.employee_id.id,
                    'partner_id':
                    self.employee_id.address_home_id.id,
                    'loan_line_ids': [(0, 0, {
                        'date': l.date,
                        'amount': l.amount,
                    }) for l in self.loan_line]
                }
                loan_pay_obj = self.env['loan.payment'].create(vals)

                loan_pay_obj.partner_type = 'customer'
                self.state = 'sent'
                return {
                    'name': 'Message',
                    'type': 'ir.actions.act_window',
                    'view_type': 'form',
                    'view_mode': 'form',
                    'res_model': 'acc.loan.payment.view.wizard',
                    'target': 'new',
                    'context': {
                        'default_name':
                        "Payment Loan Request Sent Successfully."
                    }
                }
            else:
                raise ValidationError(
                    'Related Partner of Employee is not a Customer')

        else:
            raise ValidationError('Employee does not has Related Partner')
Esempio n. 11
0
class AccountCheckbook(models.Model):

    _name = 'account.checkbook'
    _inherit = ['mail.thread']

    @api.depends('account_own_check_ids')
    def _get_checks(self):
        for checkbook in self:
            checkbook.account_draft_own_check_ids = \
                checkbook.account_own_check_ids.filtered(lambda x: x.state == 'draft')
            checkbook.account_used_own_check_ids = \
                checkbook.account_own_check_ids.filtered(lambda x: x.state != 'draft')

    @api.multi
    def _search_draft_checks(self, operator, value):
        recs = self.env['account.own.check'].search([('state', '=', 'draft')])
        return [('id', 'in', recs.ids)]

    name = fields.Char('Referencia',
                       required=True,
                       track_visibility='onchange')
    account_id = fields.Many2one(
        'account.account',
        'Cuenta',
        help=
        "Seleccionar una cuenta contable si no se desea utilizar la de la cuenta bancaria",
        track_visibility='onchange')
    payment_type = fields.Selection([('common', 'Comun'),
                                     ('postdated', 'Diferido')],
                                    string="Tipo",
                                    required=True,
                                    default='common',
                                    track_visibility='onchange')
    journal_id = fields.Many2one('account.journal',
                                 'Cuenta bancaria',
                                 domain=[('type', '=', 'bank')],
                                 required=True,
                                 track_visibility='onchange')
    account_own_check_ids = fields.One2many('account.own.check',
                                            'checkbook_id', 'Cheques')
    account_draft_own_check_ids = fields.One2many('account.own.check',
                                                  'checkbook_id',
                                                  'Cheques',
                                                  compute=_get_checks,
                                                  search=_search_draft_checks)
    account_used_own_check_ids = fields.One2many('account.own.check',
                                                 'checkbook_id',
                                                 'Cheques',
                                                 compute=_get_checks)
    number_from = fields.Char('Desde',
                              required=True,
                              track_visibility='onchange')
    number_to = fields.Char('Hasta',
                            required=True,
                            track_visibility='onchange')

    active = fields.Boolean(string='Activo',
                            default=True,
                            track_visibility='onchange')

    currency_id = fields.Many2one('res.currency',
                                  string='Moneda',
                                  related='journal_id.currency_id',
                                  readonly=True)

    @api.constrains('number_from', 'number_to')
    def constraint_numbers(self, max_checks=100):
        for checkbook in self:

            if not (checkbook.number_from.isdigit()
                    or checkbook.number_to.isdigit()):
                raise ValidationError(
                    "La numeracion debe contener solo numeros")

            if int(checkbook.number_from) <= 0 or int(
                    checkbook.number_to) <= 0:
                raise ValidationError("La numeracion debe ser mayor a cero.")

            if int(checkbook.number_from) > int(checkbook.number_to):
                raise ValidationError(
                    "Numeracion Desde no puede ser mayor a Hasta.")

            if int(checkbook.number_to) - int(
                    checkbook.number_from) + 1 > max_checks:
                raise ValidationError(
                    "El rango de cheques de la chequera es muy grande.\n"
                    "No puede superar los {} cheques".format(max_checks))

    def generate_checks(self):
        """ Crea todos los cheques faltantes de cada chequera seleccionada """

        for checkbook in self:

            if self.account_used_own_check_ids:
                raise ValidationError(
                    "Solo se pueden generar cheques en una chequera no utilizada."
                )

            total_numbers = range(int(checkbook.number_from),
                                  int(checkbook.number_to) + 1)

            checkbook._validate_checkbook_fields()
            bank_id = checkbook.journal_id.bank_id.id

            # Borramos los cheques viejos en caso que ninguno se haya usado, por si cambian el rango
            if not checkbook.account_used_own_check_ids:
                checkbook.account_own_check_ids.unlink()

            # El nombre del cheque puede contener solo digitos
            actual_numbers = [
                int(number)
                for number in checkbook.account_own_check_ids.mapped('name')
            ]

            # Creamos cheques segun la numeracion de la chequera para los cheques no existentes
            for check_number in set(total_numbers) - set(actual_numbers):
                self.account_own_check_ids.create({
                    'checkbook_id':
                    checkbook.id,
                    'name':
                    str(check_number),
                    'bank_id':
                    bank_id,
                    'payment_type':
                    checkbook.payment_type,
                    'currency_id':
                    checkbook.currency_id.id
                    or self.env.user.company_id.currency_id.id,
                })

    def _validate_checkbook_fields(self):
        if not self.journal_id.bank_id:
            raise ValidationError(
                "Falta configurar el banco en la cuenta bancaria de la chequera"
            )
Esempio n. 12
0
class DocumentPage(models.Model):
    """This class is use to manage Document."""

    _name = "document.page"
    _inherit = ['mail.thread']
    _description = "Document Page"
    _order = 'name'

    name = fields.Char('Title', required=True)

    type = fields.Selection([('content', 'Content'), ('category', 'Category')],
                            'Type',
                            help="Page type",
                            default="content")

    parent_id = fields.Many2one('document.page',
                                'Category',
                                domain=[('type', '=', 'category')])

    child_ids = fields.One2many('document.page', 'parent_id', 'Children')

    content = fields.Text("Content")

    display_content = fields.Text(string='Displayed Content',
                                  compute='_get_display_content')

    history_ids = fields.One2many('document.page.history', 'page_id',
                                  'History')

    menu_id = fields.Many2one('ir.ui.menu', "Menu", readonly=True)

    create_date = fields.Datetime("Created on", select=True, readonly=True)

    create_uid = fields.Many2one('res.users',
                                 'Author',
                                 select=True,
                                 readonly=True)

    write_date = fields.Datetime("Modification Date",
                                 select=True,
                                 readonly=True)

    write_uid = fields.Many2one('res.users',
                                "Last Contributor",
                                select=True,
                                readonly=True)

    def _get_page_index(self, page, link=True):
        """Return the index of a document."""
        index = []
        for subpage in page.child_ids:
            index += ["<li>" + self._get_page_index(subpage) + "</li>"]
        r = ''
        if link:
            r = '<a href="#id=%s">%s</a>' % (page.id, page.name)

        if index:
            r += "<ul>" + "".join(index) + "</ul>"
        return r

    def _get_display_content(self):
        """Return the content of a document."""
        for page in self:
            if page.type == "category":
                display_content = self._get_page_index(page, link=False)
            else:
                display_content = page.content
            page.display_content = display_content

    @api.onchange("parent_id")
    def do_set_content(self):
        """We Set it the right content to the new parent."""
        if self.parent_id and not self.content:
            if self.parent_id.type == "category":
                self.content = self.parent_id.content

    def create_history(self, page_id, content):
        """Create the first history of a newly created document."""
        history = self.env['document.page.history']
        return history.create({"content": content, "page_id": page_id})

    @api.multi
    def write(self, vals):
        """Write the content and set the history."""
        result = super(DocumentPage, self).write(vals)
        content = vals.get('content')
        if content:
            for page in self:
                self.create_history(page.id, content)
        return result

    @api.model
    @api.returns('self', lambda value: value.id)
    def create(self, vals):
        """Create the first history of a document."""
        page_id = super(DocumentPage, self).create(vals)
        content = vals.get('content')
        if content:
            self.create_history(page_id.id, content)
        return page_id
class sd_excel_toimport (models.Model):
    _name = "sd.excel.toimport"
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    
    name = fields.Char (string = "Description", required = True)
    state = fields.Selection (string = "State", selection = [('0', 'Draft'),
                                                             ('1', 'In progress'),
                                                             ('2', 'Imported/Done')], default = '0', required = True, readonly = True)

    model_id = fields.Many2one('ir.model', required='True', string='Select Model', help = "Type of model odoo to import")
    fields_ids = fields.Many2many ('ir.model.fields', 'ir_model_fields_sd_excel_toimport_fields', string = "To_read", depends = 'model_id', domain="[('model_id','=',model_id)]", required = True, help = "Columns from read of excel document, the order must match")
    fields_in_ids = fields.Many2many ('ir.model.fields', 'ir_model_fields_sd_excel_toimport_fields_in', string = "To import", domain="[('id','in',fields_ids[0][2]),('id','!=',field_id)]", help = "Columns from import of excel document")
    field_id = fields.Many2one ('ir.model.fields', depends = 'fields_ids', string = "Link to import", domain="[('id','in',fields_ids[0][2]),('name','in',['default_code','ref','vat','name','seller_code','ean13','email'])]", help = "Field to link between Excel and Odoo Model")
    file = fields.Binary (string = "Excel document (XLS)", help = "Document in .xls format", default = None, copy = False)
    sd_excel_line_id = fields.One2many ('sd.excel.line', 'sd_excel_toimport_id', string = "Lines to import", readonly = True)
    view_ref_id = fields.Many2one ('ir.ui.view', string = "view_ref", default = None)
    not_found = fields.Boolean (string = "Import product not found", help = "if the field is true, the not found products are created, otherwise only overwrite existing", default = False)
    auto_create = fields.Boolean (string = "Auto create", help = "If you activate this selection, the products that not created are created automaticly", default = False)
    customer = fields.Boolean (string = 'Is customer', default = False)
    supplier = fields.Boolean (string = 'Is supplier', default = False)
    
    
    @api.model
    def create (self, vals):
        res = super (sd_excel_toimport, self).create (vals)
        res.message_post (body = _("Excel import %s with name %s created" % (res.id, res.name)))
        return res
    @api.multi    
    def copy (self, default):
        default['name'] = _("%s (copy)") % self.name
        default['view_ref_id'] = None
        return super(sd_excel_toimport, self).copy (default)
        
    @api.multi
    def unlink (self):
        res = []
        for i in self:
            if i.state == '2':
                raise exceptions.Warning (_("You can't delete a import done"))
            elif i.state == '1':
                i.pool.get ('ir.ui.view').browse (i._cr, i._uid, [i.view_ref_id.id]).sudo ().unlink ()
                i.sd_excel_line_id.sudo ().unlink ()
            res.append (super (sd_excel_toimport, i).unlink ())
        return res
            
    @api.multi
    def button_read (self):
        in_progress = super (sd_excel_toimport, self).search ([('state','=','1')])
        if len (in_progress) > 0:
            msg = ''
            for i in in_progress:
                msg += str (i.name) + ' ' 
            raise exceptions.Warning (_("You must complete or delete the import %s\nThere can only be an import in progress" % msg))
        if len (self.field_id) == 1 and self.file != None and len (self.fields_in_ids) != 0:
            if self.model_id.model == "product.template":
                return self.read_excel ()
            elif self.model_id.model == "res.partner":
                return self.read_excel (True)
        elif len (self.field_id) == 0:
            raise exceptions.Warning (_("Error on Document Type\nPlease, Select link to import"))
        elif len (self.fields_in_ids) == 0:
            raise exceptions.Warning (_("Error on Document Type\nPlease, Insert fields to import"))
        elif self.file == None:
            raise exceptions.Warning (_("Error on Document Type\nPlease, Insert Excel document"))
        else:
            raise exceptions.Warning (_("Error on Document Type"))
        
    @api.multi
    def button_import (self):
        res = self.write_data ()
        if res == True:
            self.message_post (body = _("Document %s imported" % self.name))
            self.state = "2"
            self.pool.get ('ir.ui.view').browse (self._cr, self._uid, [self.view_ref_id.id]).sudo ().unlink ()   
        return res
    @api.multi
    def button_back (self):
        try:
            if self.state == '1':
                self.pool.get ('ir.ui.view').browse (self._cr, self._uid, [self.view_ref_id.id]).sudo ().unlink ()
                self.sd_excel_line_id.unlink ()
                self.message_post (body = _("Document %s change state -> Draft" % self.name))
                self.state = "0"
        except:
            raise exceptions.Warning (_("Error on delete"))
        
    @api.multi
    def read_excel (self, partner = False):
        try:
            file_path = tempfile.gettempdir () + '/' + str (self._cr.dbname) + str (self._uid) + '.xls'
            f = open (file_path, 'wb')
            f.write (self.file.decode ('base64'))
            f.close ()
            wb = xlrd.open_workbook (file_path)
            ws = wb.sheet_by_index (0)
        except:
            raise exceptions.Warning (_("Error on read Excel"))
        if len (self.fields_ids) == ws.ncols and ws.ncols <= 10:
            try:
                to_imp = []
                for i in self.fields_in_ids:
                    to_imp.append (i.id)
                for r in range (1, ws.nrows):
                    a = self.sd_excel_line_id.create ({'name': str (r),
                                                       'sd_excel_toimport_id': self.id})
                    aux = ''
                    for c in range (ws.ncols):
                        if self.field_id.name == self.fields_ids[c].name:
                            aux = self.env[str (self.model_id.model)].search ([(self.field_id.name, '=', ws.cell (r,c).value)])
                            if len (aux) > 1:
                                raise exceptions.Warning (_ ('%s %s in row %s has multiple matches' % (ws.cell (r,c).value, self.field_id.name, r)))
                            elif len (aux) <= 0:
                                aux = ''
                            break
                    for c in range(ws.ncols):
                        a.write ({'key%d' % c: ws.cell (r,c).value,})
                        if self.fields_ids[c].id in to_imp:
                            if aux != '':
                                a.write ({'old_key%d' % c: str (aux[self.fields_ids[c].name])})
                                a.write ({'ralation_model_id': aux.id})
                            else:
                                a.write ({'old_key%d' % c: _('Product not found')})
                
                self.message_post (body = _("Read Excel document %s" % self.name))
                return self.view_create (to_imp)
            except:
                raise exceptions.Warning (_("Error on write excel in sd_excel_line table"))
        else:
            raise exceptions.Warning (_("The columns of excel and number of fields don't match"))
           
    
    def view_create (self, to_imp):
        try:
            arch = """<?xml version="1.0"?>
                        <tree string="Excel Import">"""
            
            for c in range (len (self.fields_ids)):
                arch = arch + "\n<field name='key%d' string='%s'/>" % (c, self.fields_ids[c].field_description)
                if self.fields_ids[c].id in to_imp:
                    arch = arch + "\n<field name='old_key%d' string='%s'/>" % (c, _('old ') + self.fields_ids[c].field_description)
            arch = arch + "\n</tree>"
            self.view_ref_id = self.env['ir.ui.view'].sudo().create ({'name': 'view.excel.line.tree',
                                                                      'arch': arch,
                                                                      'priority': 16,
                                                                      'mode': 'primary',
                                                                      'active': 1,
                                                                      'model': 'sd.excel.line',
                                                                      'type': 'tree'})
            self.state = "1"
            return {
                    'type': 'ir.actions.act_window',
                    'res_model': 'sd.excel.toimport',
                    'view_type': 'form',
                    'view_mode': 'form',
                    'auto_refresh':1,
                    'res_id': self.id,
                    }
        except:
            raise exceptions.Warning (_("Error on view_create"))
    
    @api.multi
    def write_data (self):
        to_imp = []
        for i in self.fields_in_ids:
            to_imp.append (i.id)
        for line in self.sd_excel_line_id:
            if line.ralation_model_id:
                try:
                    key_count = 0
                    model_to_in = self.pool.get (str (self.model_id.model)).browse (self._cr, self._uid, [line.ralation_model_id])
                    for fiel in self.fields_ids:
                        if fiel.id in to_imp:
                            clave = 'key%d' % key_count
                            model_to_in.write ({str (fiel.name): line[clave]})
                        key_count += 1
                except:
                    raise exceptions.Warning (_('Error to write in %s %s' % (self.model_id.model, model_to_in.name)))
            elif self.not_found:
                try:
                    if self.auto_create:
                        key_count = 0
                        model_to_create = self.env[str (self.model_id.model)].create ({'name': 'temp'})
                        line.ralation_model_id = model_to_create.id
                        for fiel in self.fields_ids:
                            clave = 'key%d' % key_count
                            model_to_create.write ({fiel.name: line[clave]})
                            key_count += 1
                        self.message_post (body = _("Created product %s" % model_to_create.name))
                    else:
                        key_count = 0
                        model_to_create = self.env[str (self.model_id.model)].create ({'name': 'temp'})
                        line.ralation_model_id = model_to_create.id
                        for fiel in self.fields_ids:
                            clave = 'key%d' % key_count
                            model_to_create.write ({fiel.name: line[clave]})
                            key_count += 1
                        self.message_post (body = _("Created product %s" % model_to_create.name))
                        return {'name': str (self.model_id.name),
                                'type': 'ir.actions.act_window',
                                'res_model': str (self.model_id.model),
                                'view_type': 'form',
                                'view_mode': 'form',
                                'target': 'new',
                                'auto_refresh':1,
                                'res_id': model_to_create.id,
                                'flags': {'action_buttons': True},
                                }
                except:
                    raise exceptions.Warning (_('Error to create in %s %s' % (self.model_id.model, model_to_in.name))) 
        return True
Esempio n. 14
0
class res_partner(models.Model):
    _inherit = "res.partner"

    attachment_ids = fields.One2many('ir.attachment', 'partner_id',
                                     'Attachments')
Esempio n. 15
0
class dym_production_stock_lot(models.Model):
    _inherit = 'stock.production.lot'

    @api.multi
    def name_onchange(self, product_id, name):
        dom = {}
        # product_ids = self.env['product.category'].get_child_ids('Unit')
        # dom['product_id']=[('categ_id','in',product_ids)]
        product_ids = []
        if name:
            kd_mesin = name[:5]
            name = name.replace(' ', '').upper()
            kd_mesin = kd_mesin.replace(' ', '').upper()
            prod_tmpl_src = self.env["product.template"].search([
                ("kd_mesin", "=", kd_mesin)
            ])
            if prod_tmpl_src:
                for x in prod_tmpl_src:
                    prod_prod_src = self.env["product.product"].search([
                        ("product_tmpl_id", "=", x.id)
                    ])
                    if prod_prod_src:
                        for y in prod_prod_src:
                            product_ids.append(y.id)
        dom['product_id'] = [('id', 'in', product_ids)]
        return {'value': {'name': name, 'state': 'workshop'}, 'domain': dom}

    @api.multi
    def chassis_onchange(self, chassis_no):
        if chassis_no:
            chassis_no = chassis_no.replace(' ', '').upper()
            return {'value': {'chassis_no': chassis_no}}

    @api.multi
    def nosin_onchange(self, name):
        dom = {}
        product_ids = []
        if name:
            kd_mesin = name[:5]
            name = name.replace(' ', '').upper()
            kd_mesin = kd_mesin.replace(' ', '').upper()
            prod_tmpl_src = self.env["product.template"].search([
                ("kd_mesin", "=", kd_mesin)
            ])
            if prod_tmpl_src:
                for x in prod_tmpl_src:
                    prod_prod_src = self.env["product.product"].search([
                        ("product_tmpl_id", "=", x.id)
                    ])
                    if prod_prod_src:
                        for y in prod_prod_src:
                            product_ids.append(y.id)
        dom['product_id'] = [('id', 'in', product_ids)]
        return {'domain': dom}

    @api.multi
    def no_pol_onchange(self, no_polisi):
        warning = {}
        value = {}
        result = {}
        if no_polisi:
            formatted_no_polisi = ''
            no_polisi_normalize = no_polisi.replace(' ', '').upper()
            splitted_no_polisi = re.findall(r'[A-Za-z]+|\d+',
                                            no_polisi_normalize)
            if len(splitted_no_polisi) == 3:
                if splitted_no_polisi[0].isalpha(
                ) == True and splitted_no_polisi[1].isdigit(
                ) == True and splitted_no_polisi[2].isalpha() == True:
                    for word in splitted_no_polisi:
                        formatted_no_polisi += word + ' '
                    formatted_no_polisi = formatted_no_polisi[:-1]
                    return {'value': {'no_polisi': formatted_no_polisi}}
            warning = {
                'title': ('Perhatian !'),
                'message':
                (('Format nomor polisi salah, mohon isi nomor polisi dengan format yang benar! (ex. A 1234 BB)'
                  )),
            }
            value['no_polisi'] = self.no_polisi
            result['warning'] = warning
            result['value'] = value
            return result

    @api.multi
    def kode_buku_onchange(self, kode_buku):
        if kode_buku:
            kode_buku = kode_buku.replace(' ', '').upper()
            return {'value': {'kode_buku': kode_buku}}

    @api.multi
    def nama_buku_onchange(self, nama_buku):
        if nama_buku:
            nama_buku = nama_buku.replace(' ', '').upper()
            return {'value': {'nama_buku': nama_buku}}

    work_order_ids = fields.One2many('dym.work.order',
                                     'lot_id',
                                     string="Work Orders",
                                     readonly=True)

    def name_get(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        if isinstance(ids, (int, long)):
            ids = [ids]
        res = []
        for record in self.browse(cr, uid, ids, context=context):
            name = record.name
            if record.no_polisi:
                name = "%s - %s" % (record.no_polisi, name)
            res.append((record.id, name))
        return res

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=100):
        args = args or []
        if name and len(name) >= 3:
            args = [
                '|', ('name', operator, name), ('no_polisi', operator, name)
            ] + args
        categories = self.search(args, limit=limit)
        return categories.name_get()

    @api.model
    def create(self, vals):
        if not vals.get('product_id'):
            return False
        res = super(dym_production_stock_lot, self).create(vals)
        return res
Esempio n. 16
0
class AccountAssetAsset(models.Model):
    _name = 'account.asset.asset'
    _description = 'Asset/Revenue Recognition'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    account_move_ids = fields.One2many('account.move',
                                       'asset_id',
                                       string='Entries',
                                       readonly=True,
                                       states={'draft': [('readonly', False)]})
    entry_count = fields.Integer(compute='_entry_count',
                                 string='# Asset Entries')
    name = fields.Char(string='Asset Name',
                       required=True,
                       readonly=True,
                       states={'draft': [('readonly', False)]})
    code = fields.Char(string='Reference',
                       size=32,
                       readonly=True,
                       states={'draft': [('readonly', False)]})
    value = fields.Float(string='Gross Value',
                         required=True,
                         readonly=True,
                         digits=0,
                         states={'draft': [('readonly', False)]},
                         oldname='purchase_value')
    currency_id = fields.Many2one(
        'res.currency',
        string='Currency',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)]},
        default=lambda self: self.env.user.company_id.currency_id.id)
    company_id = fields.Many2one('res.company',
                                 string='Company',
                                 required=True,
                                 readonly=True,
                                 states={'draft': [('readonly', False)]},
                                 default=lambda self: self.env['res.company'].
                                 _company_default_get('account.asset.asset'))
    note = fields.Text()
    category_id = fields.Many2one('account.asset.category',
                                  string='Category',
                                  required=True,
                                  change_default=True,
                                  readonly=True,
                                  states={'draft': [('readonly', False)]})
    date = fields.Date(string='Date',
                       required=True,
                       readonly=True,
                       states={'draft': [('readonly', False)]},
                       default=fields.Date.context_today,
                       oldname="purchase_date")
    state = fields.Selection(
        [('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')],
        'Status',
        required=True,
        copy=False,
        default='draft',
        help="When an asset is created, the status is 'Draft'.\n"
        "If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n"
        "You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status."
    )
    active = fields.Boolean(default=True)
    partner_id = fields.Many2one('res.partner',
                                 string='Partner',
                                 readonly=True,
                                 states={'draft': [('readonly', False)]})
    method = fields.Selection(
        [('linear', 'Linear'), ('degressive', 'Degressive')],
        string='Computation Method',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)]},
        default='linear',
        help=
        "Choose the method to use to compute the amount of depreciation lines.\n  * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
        "  * Degressive: Calculated on basis of: Residual Value * Degressive Factor"
    )
    method_number = fields.Integer(
        string='Number of Depreciations',
        readonly=True,
        states={'draft': [('readonly', False)]},
        default=5,
        help="The number of depreciations needed to depreciate your asset")
    method_period = fields.Integer(
        string='Number of Months in a Period',
        required=True,
        readonly=True,
        default=12,
        states={'draft': [('readonly', False)]},
        help="The amount of time between two depreciations, in months")
    method_end = fields.Date(string='Ending Date',
                             readonly=True,
                             states={'draft': [('readonly', False)]})
    method_progress_factor = fields.Float(
        string='Degressive Factor',
        readonly=True,
        default=0.3,
        states={'draft': [('readonly', False)]})
    value_residual = fields.Float(compute='_amount_residual',
                                  method=True,
                                  digits=0,
                                  string='Residual Value')
    method_time = fields.Selection(
        [('number', 'Number of Depreciations'), ('end', 'Ending Date')],
        string='Time Method',
        required=True,
        readonly=True,
        default='number',
        states={'draft': [('readonly', False)]},
        help=
        "Choose the method to use to compute the dates and number of depreciation lines.\n"
        "  * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n"
        "  * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."
    )
    prorata = fields.Boolean(
        string='Prorata Temporis',
        readonly=True,
        states={'draft': [('readonly', False)]},
        help=
        'Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January / Start date of fiscal year'
    )
    depreciation_line_ids = fields.One2many('account.asset.depreciation.line',
                                            'asset_id',
                                            string='Depreciation Lines',
                                            readonly=True,
                                            states={
                                                'draft': [('readonly', False)],
                                                'open': [('readonly', False)]
                                            })
    salvage_value = fields.Float(
        string='Salvage Value',
        digits=0,
        readonly=True,
        states={'draft': [('readonly', False)]},
        help="It is the amount you plan to have that you cannot depreciate.")
    invoice_id = fields.Many2one('account.invoice',
                                 string='Invoice',
                                 states={'draft': [('readonly', False)]},
                                 copy=False)
    type = fields.Selection(related="category_id.type",
                            string='Type',
                            required=True)

    @api.multi
    def unlink(self):
        for asset in self:
            if asset.state in ['open', 'close']:
                raise UserError(
                    _('You cannot delete a document is in %s state.') %
                    (asset.state, ))
            if asset.account_move_ids:
                raise UserError(
                    _('You cannot delete a document that contains posted entries.'
                      ))
        return super(AccountAssetAsset, self).unlink()

    @api.multi
    def _get_last_depreciation_date(self):
        """
        @param id: ids of a account.asset.asset objects
        @return: Returns a dictionary of the effective dates of the last depreciation entry made for given asset ids. If there isn't any, return the purchase date of this asset
        """
        self.env.cr.execute(
            """
            SELECT a.id as id, COALESCE(MAX(m.date),a.date) AS date
            FROM account_asset_asset a
            LEFT JOIN account_move m ON (m.asset_id = a.id)
            WHERE a.id IN %s
            GROUP BY a.id, a.date """, (tuple(self.ids), ))
        result = dict(self.env.cr.fetchall())
        return result

    @api.model
    def _cron_generate_entries(self):
        assets = self.env['account.asset.asset'].search([('state', '=', 'open')
                                                         ])
        assets._compute_entries(datetime.today())

    def _compute_board_amount(self, sequence, residual_amount, amount_to_depr,
                              undone_dotation_number,
                              posted_depreciation_line_ids, total_days,
                              depreciation_date):
        amount = 0
        if sequence == undone_dotation_number:
            amount = residual_amount
        else:
            if self.method == 'linear':
                amount = amount_to_depr / (undone_dotation_number -
                                           len(posted_depreciation_line_ids))
                if self.prorata:
                    amount = amount_to_depr / self.method_number
                    if sequence == 1:
                        days = (self.company_id.compute_fiscalyear_dates(
                            depreciation_date)['date_to'] -
                                depreciation_date).days + 1
                        amount = (amount_to_depr /
                                  self.method_number) / total_days * days
            elif self.method == 'degressive':
                amount = residual_amount * self.method_progress_factor
                if self.prorata:
                    if sequence == 1:
                        days = (self.company_id.compute_fiscalyear_dates(
                            depreciation_date)['date_to'] -
                                depreciation_date).days + 1
                        amount = (residual_amount * self.method_progress_factor
                                  ) / total_days * days
        return amount

    def _compute_board_undone_dotation_nb(self, depreciation_date, total_days):
        undone_dotation_number = self.method_number
        if self.method_time == 'end':
            end_date = datetime.strptime(self.method_end, DF).date()
            undone_dotation_number = 0
            while depreciation_date <= end_date:
                depreciation_date = date(
                    depreciation_date.year, depreciation_date.month,
                    depreciation_date.day) + relativedelta(
                        months=+self.method_period)
                undone_dotation_number += 1
        if self.prorata:
            undone_dotation_number += 1
        return undone_dotation_number

    @api.multi
    def compute_depreciation_board(self):
        self.ensure_one()

        posted_depreciation_line_ids = self.depreciation_line_ids.filtered(
            lambda x: x.move_check).sorted(key=lambda l: l.depreciation_date)
        unposted_depreciation_line_ids = self.depreciation_line_ids.filtered(
            lambda x: not x.move_check)

        # Remove old unposted depreciation lines. We cannot use unlink() with One2many field
        commands = [(2, line_id.id, False)
                    for line_id in unposted_depreciation_line_ids]

        if self.value_residual != 0.0:
            amount_to_depr = residual_amount = self.value_residual
            if self.prorata:
                depreciation_date = datetime.strptime(
                    self._get_last_depreciation_date()[self.id], DF).date()
            else:
                # depreciation_date = 1st of January of purchase year if annual valuation, 1st of
                # purchase month in other cases
                if self.method_period >= 12:
                    asset_date = datetime.strptime(self.date[:4] + '-01-01',
                                                   DF).date()
                else:
                    asset_date = datetime.strptime(self.date[:7] + '-01',
                                                   DF).date()
                # if we already have some previous validated entries, starting date isn't 1st January but last entry + method period
                if posted_depreciation_line_ids and posted_depreciation_line_ids[
                        -1].depreciation_date:
                    last_depreciation_date = datetime.strptime(
                        posted_depreciation_line_ids[-1].depreciation_date,
                        DF).date()
                    depreciation_date = last_depreciation_date + relativedelta(
                        months=+self.method_period)
                else:
                    depreciation_date = asset_date
            day = depreciation_date.day
            month = depreciation_date.month
            year = depreciation_date.year
            total_days = (year % 4) and 365 or 366

            undone_dotation_number = self._compute_board_undone_dotation_nb(
                depreciation_date, total_days)

            for x in range(len(posted_depreciation_line_ids),
                           undone_dotation_number):
                sequence = x + 1
                amount = self._compute_board_amount(
                    sequence, residual_amount, amount_to_depr,
                    undone_dotation_number, posted_depreciation_line_ids,
                    total_days, depreciation_date)
                amount = self.currency_id.round(amount)
                residual_amount -= amount
                vals = {
                    'amount':
                    amount,
                    'asset_id':
                    self.id,
                    'sequence':
                    sequence,
                    'name': (self.code or '') + '/' + str(sequence),
                    'remaining_value':
                    residual_amount,
                    'depreciated_value':
                    self.value - (self.salvage_value + residual_amount),
                    'depreciation_date':
                    depreciation_date.strftime(DF),
                }
                commands.append((0, False, vals))
                # Considering Depr. Period as months
                depreciation_date = date(year, month, day) + relativedelta(
                    months=+self.method_period)
                day = depreciation_date.day
                month = depreciation_date.month
                year = depreciation_date.year

        self.write({'depreciation_line_ids': commands})

        return True

    @api.multi
    def validate(self):
        self.write({'state': 'open'})
        fields = [
            'method',
            'method_number',
            'method_period',
            'method_end',
            'method_progress_factor',
            'method_time',
            'salvage_value',
            'invoice_id',
        ]
        ref_tracked_fields = self.env['account.asset.asset'].fields_get(fields)
        for asset in self:
            tracked_fields = ref_tracked_fields.copy()
            if asset.method == 'linear':
                del (tracked_fields['method_progress_factor'])
            if asset.method_time != 'end':
                del (tracked_fields['method_end'])
            else:
                del (tracked_fields['method_number'])
            dummy, tracking_value_ids = asset._message_track(
                tracked_fields, dict.fromkeys(fields))
            asset.message_post(subject=_('Asset created'),
                               tracking_value_ids=tracking_value_ids)

    @api.multi
    def set_to_close(self):
        move_ids = []
        for asset in self:
            unposted_depreciation_line_ids = asset.depreciation_line_ids.filtered(
                lambda x: not x.move_check)
            if unposted_depreciation_line_ids:
                old_values = {
                    'method_end': asset.method_end,
                    'method_number': asset.method_number,
                }

                # Remove all unposted depr. lines
                commands = [(2, line_id.id, False)
                            for line_id in unposted_depreciation_line_ids]

                # Create a new depr. line with the residual amount and post it
                sequence = len(asset.depreciation_line_ids) - len(
                    unposted_depreciation_line_ids) + 1
                today = datetime.today().strftime(DF)
                vals = {
                    'amount': asset.value_residual,
                    'asset_id': asset.id,
                    'sequence': sequence,
                    'name': (asset.code or '') + '/' + str(sequence),
                    'remaining_value': 0,
                    'depreciated_value': asset.value -
                    asset.salvage_value,  # the asset is completely depreciated
                    'depreciation_date': today,
                }
                commands.append((0, False, vals))
                asset.write({
                    'depreciation_line_ids': commands,
                    'method_end': today,
                    'method_number': sequence
                })
                tracked_fields = self.env['account.asset.asset'].fields_get(
                    ['method_number', 'method_end'])
                changes, tracking_value_ids = asset._message_track(
                    tracked_fields, old_values)
                if changes:
                    asset.message_post(subject=_(
                        'Asset sold or disposed. Accounting entry awaiting for validation.'
                    ),
                                       tracking_value_ids=tracking_value_ids)
                move_ids += asset.depreciation_line_ids[-1].create_move(
                    post_move=False)
        if move_ids:
            name = _('Disposal Move')
            view_mode = 'form'
            if len(move_ids) > 1:
                name = _('Disposal Moves')
                view_mode = 'tree,form'
            return {
                'name': name,
                'view_type': 'form',
                'view_mode': view_mode,
                'res_model': 'account.move',
                'type': 'ir.actions.act_window',
                'target': 'current',
                'res_id': move_ids[0],
            }

    @api.multi
    def set_to_draft(self):
        self.write({'state': 'draft'})

    @api.one
    @api.depends('value', 'salvage_value', 'depreciation_line_ids.move_check',
                 'depreciation_line_ids.amount')
    def _amount_residual(self):
        total_amount = 0.0
        for line in self.depreciation_line_ids:
            if line.move_check:
                total_amount += line.amount
        self.value_residual = self.value - total_amount - self.salvage_value

    @api.onchange('company_id')
    def onchange_company_id(self):
        self.currency_id = self.company_id.currency_id.id

    @api.multi
    @api.depends('account_move_ids')
    def _entry_count(self):
        for asset in self:
            asset.entry_count = self.env['account.move'].search_count([
                ('asset_id', '=', asset.id)
            ])

    @api.one
    @api.constrains('prorata', 'method_time')
    def _check_prorata(self):
        if self.prorata and self.method_time != 'number':
            raise ValidationError(
                _('Prorata temporis can be applied only for time method "number of depreciations".'
                  ))

    @api.onchange('category_id')
    def onchange_category_id(self):
        vals = self.onchange_category_id_values(self.category_id.id)
        # We cannot use 'write' on an object that doesn't exist yet
        if vals:
            for k, v in vals['value'].iteritems():
                setattr(self, k, v)

    def onchange_category_id_values(self, category_id):
        if category_id:
            category = self.env['account.asset.category'].browse(category_id)
            return {
                'value': {
                    'method': category.method,
                    'method_number': category.method_number,
                    'method_time': category.method_time,
                    'method_period': category.method_period,
                    'method_progress_factor': category.method_progress_factor,
                    'method_end': category.method_end,
                    'prorata': category.prorata,
                }
            }

    @api.onchange('method_time')
    def onchange_method_time(self):
        if self.method_time != 'number':
            self.prorata = False

    @api.multi
    def copy_data(self, default=None):
        if default is None:
            default = {}
        default['name'] = self.name + _(' (copy)')
        return super(AccountAssetAsset, self).copy_data(default)[0]

    @api.multi
    def _compute_entries(self, date):
        depreciation_ids = self.env['account.asset.depreciation.line'].search([
            ('asset_id', 'in', self.ids), ('depreciation_date', '<=', date),
            ('move_check', '=', False)
        ])
        return depreciation_ids.create_move()

    @api.model
    def create(self, vals):
        asset = super(AccountAssetAsset,
                      self.with_context(mail_create_nolog=True)).create(vals)
        asset.compute_depreciation_board()
        return asset

    @api.multi
    def write(self, vals):
        res = super(AccountAssetAsset, self).write(vals)
        if 'depreciation_line_ids' not in vals and 'state' not in vals:
            for rec in self:
                rec.compute_depreciation_board()
        return res

    @api.multi
    def open_entries(self):
        return {
            'name':
            _('Journal Entries'),
            'view_type':
            'form',
            'view_mode':
            'tree,form',
            'res_model':
            'account.move',
            'view_id':
            False,
            'type':
            'ir.actions.act_window',
            'context':
            dict(self.env.context or {},
                 search_default_asset_id=self.id,
                 default_asset_id=self.id),
        }
class ReportIntrastatCode(models.Model):
    _name = "report.intrastat.code"
    _description = "H.S. Code"
    _order = "name"
    _rec_name = "display_name"

    @api.one
    @api.depends('name', 'description')
    def _compute_display_name(self):
        display_name = self.name or ''
        if self.description:
            display_name += ' ' + self.description
        self.display_name = display_name

    name = fields.Char(
        string='H.S. code',
        help="Full length Harmonized System code (digits only). Full list is "
        "available from the World Customs Organisation, see "
        "http://www.wcoomd.org")
    description = fields.Char(
        'Description', help="Short text description of the H.S. category")
    display_name = fields.Char(compute='_compute_display_name',
                               string="Display Name",
                               readonly=True,
                               store=True)
    intrastat_code = fields.Char(
        string='European Intrastat Code',
        size=9,
        required=True,
        help="Code used for the Intrastat declaration. Must be part "
        "of the 'Combined Nomenclature' (CN), cf "
        "http://en.wikipedia.org/wiki/Combined_Nomenclature"
        "Must have 8 digits with sometimes a 9th digit.")
    intrastat_uom_id = fields.Many2one(
        'product.uom',
        string='UoM for Intrastat Report',
        help="Select the unit of measure if one is required for "
        "this particular Intrastat Code (other than the weight in Kg). "
        "If no particular unit of measure is required, leave empty.")
    active = fields.Boolean(default=True)
    product_categ_ids = fields.One2many('product.category',
                                        'intrastat_id',
                                        string='Product Categories')
    product_tmpl_ids = fields.One2many('product.template',
                                       'intrastat_id',
                                       string='Products')

    @api.constrains('name', 'intrastat_code')
    def _hs_code(self):
        if self.name and not self.name.isdigit():
            raise ValidationError(
                _("H.S. codes should only contain digits. It is not the case "
                  "of H.S. code '%s'.") % self.name)
        if self.intrastat_code and not self.intrastat_code.isdigit():
            raise ValidationError(
                _("The field Intrastat Code should only contain digits. "
                  "It is not the case of Intrastat Code '%s'.") %
                self.intrastat_code)
        if self.intrastat_code and len(self.intrastat_code) not in (8, 9):
            raise ValidationError(
                _("The field Intrastat Code should "
                  "contain 8 or 9 digits. It is not the case of "
                  "Intrastat Code '%s'.") % self.intrastat_code)

    _sql_constraints = [('hs_code_uniq', 'unique(name)',
                         'This H.S. code already exists in Odoo !')]

    @api.model
    @api.returns('self', lambda value: value.id)
    def create(self, vals):
        if vals.get('intrastat_code'):
            vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '')
        return super(ReportIntrastatCode, self).create(vals)

    @api.multi
    def write(self, vals):
        if vals.get('intrastat_code'):
            vals['intrastat_code'] = vals['intrastat_code'].replace(' ', '')
        return super(ReportIntrastatCode, self).write(vals)
Esempio n. 18
0
class account_voucher(models.Model):

    _inherit = 'account.voucher'

    received_third_check_ids = fields.One2many(
        'account.check',
        'voucher_id',
        'Third Checks',
        domain=[('type', '=', 'third')],
        context={
            'default_type': 'third',
            'from_voucher': True
        },
        required=False,
        readonly=True,
        copy=False,
        states={'draft': [('readonly', False)]})
    issued_check_ids = fields.One2many('account.check',
                                       'voucher_id',
                                       'Issued Checks',
                                       domain=[('type', '=', 'issue')],
                                       context={
                                           'default_type': 'issue',
                                           'from_voucher': True
                                       },
                                       copy=False,
                                       required=False,
                                       readonly=True,
                                       states={'draft': [('readonly', False)]})
    delivered_third_check_ids = fields.One2many(
        'account.check',
        'third_handed_voucher_id',
        'Third Checks',
        domain=[('type', '=', 'third')],
        copy=False,
        context={'from_voucher': True},
        required=False,
        readonly=True,
        states={'draft': [('readonly', False)]})
    validate_only_checks = fields.Boolean(
        related='journal_id.validate_only_checks',
        string='Validate only Checks',
        readonly=True,
    )
    check_type = fields.Selection(
        related='journal_id.check_type',
        string='Check Type',
        readonly=True,
    )
    dummy_journal_id = fields.Many2one(
        related='journal_id',
        readonly=True,
        string='Dummy Journa',
        help='Field used for new api onchange methods over journal',
    )
    amount_readonly = fields.Float(
        related='amount',
        string='Total',
        digits_compute=dp.get_precision('Account'),
        readonly=True,
    )

    @api.onchange('dummy_journal_id')
    def change_dummy_journal_id(self):
        """Unlink checks on journal change"""
        self.delivered_third_check_ids = False
        self.issued_check_ids = False
        self.received_third_check_ids = False

    @api.multi
    def action_cancel_draft(self):
        res = super(account_voucher, self).action_cancel_draft()
        checks = self.env['account.check'].search([('voucher_id', 'in',
                                                    self.ids)])
        checks.action_cancel_draft()
        return res

    @api.model
    def first_move_line_get(self, voucher_id, move_id, company_currency,
                            current_currency):
        vals = super(account_voucher,
                     self).first_move_line_get(voucher_id, move_id,
                                               company_currency,
                                               current_currency)
        voucher = self.browse(voucher_id)
        if company_currency != current_currency and voucher.amount:
            debit = vals.get('debit')
            credit = vals.get('credit')
            total = debit - credit
            exchange_rate = total / voucher.amount
            checks = []
            if voucher.check_type == 'third':
                checks = voucher.received_third_check_ids
            elif voucher.check_type == 'issue':
                checks = voucher.issued_check_ids
            for check in checks:
                company_currency_amount = abs(check.amount * exchange_rate)
                check.company_currency_amount = company_currency_amount
        return vals

    @api.multi
    def cancel_voucher(self):
        for voucher in self:
            for check in voucher.received_third_check_ids:
                if check.state not in ['draft', 'holding']:
                    raise Warning(
                        _('You can not cancel a voucher thas has received third checks in states other than "draft or "holding". First try to change check state.'
                          ))
            for check in voucher.issued_check_ids:
                if check.state not in ['draft', 'handed']:
                    raise Warning(
                        _('You can not cancel a voucher thas has issue checks in states other than "draft or "handed". First try to change check state.'
                          ))
            for check in voucher.delivered_third_check_ids:
                if check.state not in ['handed']:
                    raise Warning(
                        _('You can not cancel a voucher thas has delivered checks in states other than "handed". First try to change check state.'
                          ))
        res = super(account_voucher, self).cancel_voucher()
        checks = self.env['account.check'].search([
            '|', ('voucher_id', 'in', self.ids),
            ('third_handed_voucher_id', 'in', self.ids)
        ])
        for check in checks:
            check.signal_workflow('cancel')
        return res

    def proforma_voucher(self, cr, uid, ids, context=None):
        res = super(account_voucher, self).proforma_voucher(cr,
                                                            uid,
                                                            ids,
                                                            context=None)
        for voucher in self.browse(cr, uid, ids, context=context):
            if voucher.type == 'payment':
                for check in voucher.issued_check_ids:
                    check.signal_workflow('draft_router')
                for check in voucher.delivered_third_check_ids:
                    check.signal_workflow('holding_handed')
            elif voucher.type == 'receipt':
                for check in voucher.received_third_check_ids:
                    check.signal_workflow('draft_router')
        return res

    @api.one
    @api.onchange('amount_readonly')
    def onchange_amount_readonly(self):
        self.amount = self.amount_readonly

    @api.one
    @api.onchange('received_third_check_ids', 'issued_check_ids')
    def onchange_customer_checks(self):
        self.amount_readonly = sum(x.amount
                                   for x in self.received_third_check_ids)

    @api.one
    @api.onchange('delivered_third_check_ids', 'issued_check_ids')
    def onchange_supplier_checks(self):
        amount = sum(x.amount for x in self.delivered_third_check_ids)
        amount += sum(x.amount for x in self.issued_check_ids)
        self.amount_readonly = amount
Esempio n. 19
0
class settlement_agent(models.Model):
    """Agent's settlement"""

    _name = 'settlement.agent'

    def _invoice_line_hook(self,
                           cursor,
                           user,
                           move_line,
                           invoice_line_id,
                           context=None):
        '''Call after the creation of the invoice line'''
        return

    def _get_address_invoice(self, cr, uid, settlement, context=None):
        """Return
        {
            'default: address,
            'contact': address,
            'invoice': address
        } for invoice
        """
        partner_obj = self.pool['res.partner']
        partner = settlement.agent_id.partner_id
        return partner_obj.address_get(cr,
                                       uid, [partner.id],
                                       ['default', 'contact', 'invoice'],
                                       context=context)

    def _invoice_hook(self, cr, uid, picking, invoice_id, context=None):
        '''Call after the creation of the invoice'''
        return

    agent_id = fields.Many2one("sale.agent",
                               string="Agent",
                               required=True,
                               select=1)

    total_per = fields.Float(string="Total percentages", readonly=True)
    total_sections = fields.Float(string="Total sections", readonly=True)

    total = fields.Float(string="Total", readonly=True)

    lines = fields.One2many("settlement.line",
                            "settlement_agent_id",
                            string="Lines",
                            readonly=True)

    invoices = fields.One2many("settled.invoice.agent",
                               "settlement_agent_id",
                               string="Invoices",
                               readonly=True)

    settlement_id = fields.Many2one("settlement",
                                    string="Settlement",
                                    required=True,
                                    ondelete="cascade")

    def get_currency_id(self, cr, uid, picking, context=None):
        return False

    def action_invoice_create(self,
                              cr,
                              uid,
                              ids,
                              journal_id,
                              product_id,
                              context=None):
        '''Return ids of created invoices for the settlements'''
        invoice_obj = self.pool['account.invoice']
        invoice_line_obj = self.pool['account.invoice.line']
        product_pool = self.pool['product.product']
        account_fiscal_position_pool = self.pool['account.fiscal.position']
        res = {}
        for settlement in self.browse(cr, uid, ids, context=context):
            payment_term_id = False
            partner = settlement.agent_id and settlement.agent_id.partner_id
            if not partner:
                raise exceptions.Warning(
                    _("Agent to settle hasn't assigned partner."))
            # Invoice is from a supplier
            account_id = partner.property_account_payable.id
            address_default_id, address_contact_id, address_invoice_id = (
                self._get_address_invoice(cr, uid, settlement,
                                          context=context).values())

            # Don't group
            invoice_vals = {
                'name': settlement.settlement_id.name,
                'origin': (settlement.settlement_id.name or ''),
                'type': 'in_invoice',
                'account_id': account_id,
                'partner_id': partner.id,
                'address_invoice_id': address_invoice_id,
                'address_contact_id': address_contact_id,
                'payment_term': payment_term_id,
                'fiscal_position': partner.property_account_position.id
            }
            cur_id = self.get_currency_id(cr, uid, settlement, context=context)
            if cur_id:
                invoice_vals['currency_id'] = cur_id
            if journal_id:
                invoice_vals['journal_id'] = journal_id
            invoice_id = invoice_obj.create(cr,
                                            uid,
                                            invoice_vals,
                                            context=context)
            res[settlement.id] = invoice_id
            # The product is chosen in the appropriate wizard
            product = product_pool.browse(cr, uid, product_id, context=context)
            account_id = product.product_tmpl_id.property_account_expense.id
            if not account_id:
                account_id = product.categ_id.property_account_expense_categ.id
            # Tax calculations to be applied
            taxes = []
            if product.supplier_taxes_id:
                taxes.append(product.supplier_taxes_id)

            # Append the retention associated to the agent
            if settlement.agent_id and settlement.agent_id.retention_id:
                taxes.append(settlement.agent_id.retention_id)
            if settlement.agent_id and settlement.agent_id.partner_id:
                tax_ids = self.pool.get('account.fiscal.position').map_tax(
                    cr, uid,
                    settlement.agent_id.partner_id.property_account_position,
                    taxes)
            else:
                tax_ids = map(lambda x: x.id, taxes)
            for invoice in settlement.invoices:
                origin = invoice.invoice_number
                name = invoice.invoice_number
                price_unit = invoice.settled_amount
                discount = 0
                # set UoS if it's a sale and the picking doesn't have one
                uos_id = False
                account_id = account_fiscal_position_pool.map_account(
                    cr,
                    uid,
                    partner.property_account_position,
                    account_id,
                    context=context)
                invoice_line_id = invoice_line_obj.create(
                    cr,
                    uid, {
                        'name': name,
                        'origin': origin,
                        'invoice_id': invoice_id,
                        'uos_id': uos_id,
                        'product_id': product.id,
                        'account_id': account_id,
                        'price_unit': price_unit,
                        'discount': discount,
                        'quantity': 1,
                        'invoice_line_tax_id': [(6, 0, tax_ids)],
                    },
                    context=context)
                self._invoice_line_hook(cr,
                                        uid,
                                        invoice,
                                        invoice_line_id,
                                        context=context)
            invoice_obj.button_compute(cr,
                                       uid, [invoice_id],
                                       context=context,
                                       set_total=(type in ('in_invoice',
                                                           'in_refund')))
            self._invoice_hook(cr,
                               uid,
                               settlement,
                               invoice_id,
                               context=context)
        return res

    def calculate(self, cr, uid, ids, date_from, date_to, context=None):
        settlement_line_pool = self.pool['settlement.line']
        invoice_line_agent_pool = self.pool['invoice.line.agent']
        set_agent = self.browse(cr, uid, ids, context=context)
        user = self.pool['res.users'].browse(cr, uid, uid, context=context)
        # Recalculate all the line that has commission
        sql = """
            SELECT  invoice_line_agent.id FROM account_invoice_line
                INNER JOIN invoice_line_agent
                ON invoice_line_agent.invoice_line_id=account_invoice_line.id
                INNER JOIN account_invoice
                ON account_invoice_line.invoice_id = account_invoice.id
            WHERE invoice_line_agent.agent_id={}
                AND invoice_line_agent.settled=True
                AND account_invoice.state<>'draft'
                AND account_invoice.type='out_invoice'
                AND account_invoice.date_invoice >= '{}'
                AND account_invoice.date_invoice <= '{}'
                AND account_invoice.company_id = {}
            """.format(set_agent.agent_id.id, date_from, date_to,
                       user.company_id.id)
        cr.execute(sql)
        res = cr.fetchall()
        inv_line_agent_ids = [x[0] for x in res]
        invoice_line_agent_pool.calculate_commission(cr,
                                                     uid,
                                                     inv_line_agent_ids,
                                                     context=context)
        sql = """
            SELECT  account_invoice_line.id FROM account_invoice_line
            INNER JOIN invoice_line_agent
                ON invoice_line_agent.invoice_line_id=account_invoice_line.id
            INNER JOIN account_invoice
                ON account_invoice_line.invoice_id = account_invoice.id
            WHERE invoice_line_agent.agent_id={}
                AND invoice_line_agent.settled=False
                AND account_invoice.state<>'draft'
                AND account_invoice.type='out_invoice'
                AND account_invoice.date_invoice >= '{}'
                AND account_invoice.date_invoice <= '{}'
                AND account_invoice.company_id = {}""".format(
            set_agent.agent_id.id, date_from, date_to, user.company_id.id)
        cr.execute(sql)
        res = cr.fetchall()
        inv_line_ids = [x[0] for x in res]
        total_per = 0
        total_sections = 0
        sections = {}
        for inv_line_id in inv_line_ids:
            linea_id = settlement_line_pool.create(
                cr,
                uid, {
                    'invoice_line_id': inv_line_id,
                    'settlement_agent_id': ids
                },
                context=context)
            settlement_line_pool.calculate(cr, uid, linea_id, context=context)
            line = settlement_line_pool.browse(cr,
                                               uid,
                                               linea_id,
                                               context=context)
            # Mark the commission in the invoice as settled
            # and calculate the quantity
            # If we use sections then the quantity is zero,
            # although will reflect the Agent
            if line.commission_id.commission_type == "fixed":
                total_per = total_per + line.commission
                inv_ag_ids = invoice_line_agent_pool.search(
                    cr,
                    uid, [('invoice_line_id', '=', inv_line_id),
                          ('agent_id', '=', set_agent.agent_id.id)],
                    context=context)

                invoice_line_agent_pool.write(cr,
                                              uid,
                                              inv_ag_ids, {
                                                  'settled': True,
                                                  'quantity': line.commission
                                              },
                                              context=context)
            product_id = line.invoice_line_id.product_id
            is_commission_free = product_id.commission_free
            if (line.commission_id.commission_type == "section"
                    and not is_commission_free):
                # We aggregate the base value by grouping
                # by the distinct sections that the agent
                # has assigned for it
                if line.commission_id.id in sections:
                    sections[line.commission_id.id]['base'] = (
                        sections[line.commission_id.id]['base'] +
                        line.invoice_line_id.price_subtotal)
                    # Append the lines for the calculation by sections
                    sections[line.commission_id.id]['lines'].append(line)
                else:
                    sections[line.commission_id.id] = {
                        'type': line.commission_id,
                        'base': line.invoice_line_id.price_subtotal,
                        'lines': [line]
                    }
        # Iterate over each section created
        for tramo in sections:
            # Calculate the commision for each section
            tramo = sections[tramo]
            sections[tramo].update(
                {'commission': tramo['type'].calcula_tramos(tramo['base'])})
            total_sections = total_sections + sections[tramo]['commission']
            # Split the commision for each line
            for linea_tramo in sections[tramo]['lines']:
                subtotal = linea_tramo.invoice_line_id.price_subtotal
                com_por_linea = (sections[tramo]['commission'] *
                                 (subtotal / sections[tramo]['base']))
                linea_tramo.write({'commission': com_por_linea})
                inv_ag_ids = invoice_line_agent_pool.search(
                    cr,
                    uid,
                    [('invoice_line_id', '=', linea_tramo.invoice_line_id.id),
                     ('agent_id', '=', set_agent.agent_id.id)],
                    context=context)
                invoice_line_agent_pool.write(cr,
                                              uid,
                                              inv_ag_ids, {
                                                  'settled': True,
                                                  'quantity': com_por_linea
                                              },
                                              context=context)
        total = total_per + total_sections
        self.write(cr,
                   uid,
                   ids, {
                       'total_per': total_per,
                       'total_sections': total_sections,
                       'total': total
                   },
                   context=context)
Esempio n. 20
0
class ReportAccountFinancialReport(models.Model):
    _name = "account.financial.html.report"
    _description = "Account Report"

    name = fields.Char(translate=True)
    debit_credit = fields.Boolean('Show Credit and Debit Columns')
    line_ids = fields.One2many('account.financial.html.report.line',
                               'financial_report_id',
                               string='Lines')
    report_type = fields.Selection(
        [('date_range', 'Based on date ranges'),
         ('date_range_extended',
          "Based on date ranges with 'older' and 'total' columns and last 3 months"
          ), ('no_date_range', 'Based on a single date'),
         ('date_range_cash', 'Bases on date ranges and cash basis method')],
        string='Analysis Periods',
        default=False,
        required=True,
        help=
        'For report like the balance sheet that do not work with date ranges')
    company_id = fields.Many2one('res.company', string='Company')
    menuitem_created = fields.Boolean("Menu Has Been Created", default=False)
    parent_id = fields.Many2one('ir.ui.menu')

    def create_action_and_menu(self, parent_id):
        client_action = self.env['ir.actions.client'].create({
            'name':
            self.get_title(),
            'tag':
            'account_report_generic',
            'context': {
                'url':
                '/account_reports/output_format/financial_report/' +
                str(self.id),
                'model':
                'account.financial.html.report',
                'id':
                self.id,
            },
        })
        self.env['ir.ui.menu'].create({
            'name':
            self.get_title(),
            'parent_id':
            parent_id or self.env['ir.model.data'].xmlid_to_res_id(
                'account.menu_finance_reports'),
            'action':
            'ir.actions.client,%s' % (client_action.id, ),
        })
        self.write({'menuitem_created': True})

    @api.model
    def create(self, vals):
        parent_id = False
        if vals.get('parent_id'):
            parent_id = vals['parent_id']
            del vals['parent_id']
        res = super(ReportAccountFinancialReport, self).create(vals)
        res.create_action_and_menu(parent_id)
        return res

    @api.multi
    def get_lines(self, context_id, line_id=None):
        if isinstance(context_id, int):
            context_id = self.env[
                'account.financial.html.report.context'].browse(context_id)
        line_obj = self.line_ids
        if line_id:
            line_obj = self.env['account.financial.html.report.line'].search([
                ('id', '=', line_id)
            ])
        if context_id.comparison:
            line_obj = line_obj.with_context(
                periods=context_id.get_cmp_periods())
        used_currency = self.env.user.company_id.currency_id
        currency_table = {}
        for company in self.env['res.company'].search([]):
            if company.currency_id != used_currency:
                currency_table[
                    company.currency_id.
                    id] = used_currency.rate / company.currency_id.rate
        linesDicts = [{} for _ in context_id.get_periods()]
        res = line_obj.with_context(
            state=context_id.all_entries and 'all' or 'posted',
            cash_basis=self.report_type == 'date_range_cash'
            or context_id.cash_basis,
            strict_range=self.report_type == 'date_range_extended',
            aged_balance=self.report_type == 'date_range_extended',
            company_ids=context_id.company_ids.ids,
            context=context_id).get_lines(self, context_id, currency_table,
                                          linesDicts)
        return res

    def get_title(self):
        return self.name

    def get_name(self):
        return 'financial_report'

    @api.multi
    def get_report_type(self):
        return self.report_type

    def get_template(self):
        return 'account_reports.report_financial'
Esempio n. 21
0
File: sale.py Progetto: eksotama/OCB
class SaleOrder(models.Model):
    _name = "sale.order"
    _inherit = ['mail.thread', 'ir.needaction_mixin']
    _description = "Sales Order"
    _order = 'date_order desc, id desc'

    @api.depends('order_line.price_total')
    def _amount_all(self):
        """
        Compute the total amounts of the SO.
        """
        for order in self:
            amount_untaxed = amount_tax = 0.0
            for line in order.order_line:
                amount_untaxed += line.price_subtotal
                amount_tax += line.price_tax
            order.update({
                'amount_untaxed':
                order.pricelist_id.currency_id.round(amount_untaxed),
                'amount_tax':
                order.pricelist_id.currency_id.round(amount_tax),
                'amount_total':
                amount_untaxed + amount_tax,
            })

    @api.depends('state', 'order_line.invoice_status')
    def _get_invoiced(self):
        """
        Compute the invoice status of a SO. 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: if any SO line is 'to invoice', the whole SO is 'to invoice'
        - invoiced: if all SO lines are invoiced, the SO is invoiced.
        - upselling: if all SO lines are invoiced or upselling, the status is upselling.

        The invoice_ids are obtained thanks to the invoice lines of the SO lines, and we also search
        for possible refunds created directly from existing invoices. This is necessary since such a
        refund is not directly linked to the SO.
        """
        for order in self:
            invoice_ids = order.order_line.mapped('invoice_lines').mapped(
                'invoice_id')
            # Search for refunds as well
            refund_ids = self.env['account.invoice'].browse()
            if invoice_ids:
                refund_ids = refund_ids.search([
                    ('type', '=', 'out_refund'),
                    ('origin', 'in', invoice_ids.mapped('number'))
                ])

            line_invoice_status = [
                line.invoice_status for line in order.order_line
            ]

            if order.state not in ('sale', 'done'):
                invoice_status = 'no'
            elif any(invoice_status == 'to invoice'
                     for invoice_status in line_invoice_status):
                invoice_status = 'to invoice'
            elif all(invoice_status == 'invoiced'
                     for invoice_status in line_invoice_status):
                invoice_status = 'invoiced'
            elif all(invoice_status in ['invoiced', 'upselling']
                     for invoice_status in line_invoice_status):
                invoice_status = 'upselling'
            else:
                invoice_status = 'no'

            order.update({
                'invoice_count':
                len(set(invoice_ids.ids + refund_ids.ids)),
                'invoice_ids':
                invoice_ids.ids + refund_ids.ids,
                'invoice_status':
                invoice_status
            })

    @api.model
    def _default_note(self):
        return self.env.user.company_id.sale_note

    @api.model
    def _get_default_team(self):
        default_team_id = self.env['crm.team']._get_default_team_id()
        return self.env['crm.team'].browse(default_team_id)

    @api.onchange('fiscal_position_id')
    def _compute_tax_id(self):
        """
        Trigger the recompute of the taxes if the fiscal position is changed on the SO.
        """
        for order in self:
            order.order_line._compute_tax_id()

    name = fields.Char(string='Order Reference',
                       required=True,
                       copy=False,
                       readonly=True,
                       index=True,
                       default='New')
    origin = fields.Char(
        string='Source Document',
        help=
        "Reference of the document that generated this sales order request.")
    client_order_ref = fields.Char(string='Customer Reference', copy=False)

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('sale', 'Sale Order'),
        ('done', 'Done'),
        ('cancel', 'Cancelled'),
    ],
                             string='Status',
                             readonly=True,
                             copy=False,
                             index=True,
                             track_visibility='onchange',
                             default='draft')
    date_order = fields.Datetime(string='Order Date',
                                 required=True,
                                 readonly=True,
                                 index=True,
                                 states={
                                     'draft': [('readonly', False)],
                                     'sent': [('readonly', False)]
                                 },
                                 copy=False,
                                 default=fields.Datetime.now)
    validity_date = fields.Date(string='Expiration Date',
                                readonly=True,
                                states={
                                    'draft': [('readonly', False)],
                                    'sent': [('readonly', False)]
                                })
    create_date = fields.Datetime(string='Creation Date',
                                  readonly=True,
                                  index=True,
                                  help="Date on which sales order is created.")

    user_id = fields.Many2one('res.users',
                              string='Salesperson',
                              index=True,
                              track_visibility='onchange',
                              default=lambda self: self.env.user)
    partner_id = fields.Many2one('res.partner',
                                 string='Customer',
                                 readonly=True,
                                 states={
                                     'draft': [('readonly', False)],
                                     'sent': [('readonly', False)]
                                 },
                                 required=True,
                                 change_default=True,
                                 index=True,
                                 track_visibility='always')
    partner_invoice_id = fields.Many2one(
        'res.partner',
        string='Invoice Address',
        readonly=True,
        required=True,
        states={
            'draft': [('readonly', False)],
            'sent': [('readonly', False)]
        },
        help="Invoice address for current sales order.")
    partner_shipping_id = fields.Many2one(
        'res.partner',
        string='Delivery Address',
        readonly=True,
        required=True,
        states={
            'draft': [('readonly', False)],
            'sent': [('readonly', False)]
        },
        help="Delivery address for current sales order.")

    pricelist_id = fields.Many2one('product.pricelist',
                                   string='Pricelist',
                                   required=True,
                                   readonly=True,
                                   states={
                                       'draft': [('readonly', False)],
                                       'sent': [('readonly', False)]
                                   },
                                   help="Pricelist for current sales order.")
    currency_id = fields.Many2one("res.currency",
                                  related='pricelist_id.currency_id',
                                  string="Currency",
                                  readonly=True,
                                  required=True)
    project_id = fields.Many2one(
        'account.analytic.account',
        'Analytic Account',
        readonly=True,
        states={
            'draft': [('readonly', False)],
            'sent': [('readonly', False)]
        },
        help="The analytic account related to a sales order.",
        copy=False)

    order_line = fields.One2many('sale.order.line',
                                 'order_id',
                                 string='Order Lines',
                                 states={
                                     'cancel': [('readonly', True)],
                                     'done': [('readonly', True)]
                                 },
                                 copy=True)

    invoice_count = fields.Integer(string='# of Invoices',
                                   compute='_get_invoiced',
                                   readonly=True)
    invoice_ids = fields.Many2many("account.invoice",
                                   string='Invoices',
                                   compute="_get_invoiced",
                                   readonly=True,
                                   copy=False)
    invoice_status = fields.Selection([('upselling', 'Upselling Opportunity'),
                                       ('invoiced', 'Fully Invoiced'),
                                       ('to invoice', 'To Invoice'),
                                       ('no', 'Nothing to Invoice')],
                                      string='Invoice Status',
                                      compute='_get_invoiced',
                                      store=True,
                                      readonly=True,
                                      default='no')

    note = fields.Text('Terms and conditions', default=_default_note)

    amount_untaxed = fields.Monetary(string='Untaxed Amount',
                                     store=True,
                                     readonly=True,
                                     compute='_amount_all',
                                     track_visibility='always')
    amount_tax = fields.Monetary(string='Taxes',
                                 store=True,
                                 readonly=True,
                                 compute='_amount_all',
                                 track_visibility='always')
    amount_total = fields.Monetary(string='Total',
                                   store=True,
                                   readonly=True,
                                   compute='_amount_all',
                                   track_visibility='always')

    payment_term_id = fields.Many2one('account.payment.term',
                                      string='Payment Term',
                                      oldname='payment_term')
    fiscal_position_id = fields.Many2one('account.fiscal.position',
                                         oldname='fiscal_position',
                                         string='Fiscal Position')
    company_id = fields.Many2one('res.company',
                                 'Company',
                                 default=lambda self: self.env['res.company'].
                                 _company_default_get('sale.order'))
    team_id = fields.Many2one('crm.team',
                              'Sales Team',
                              change_default=True,
                              default=_get_default_team)
    procurement_group_id = fields.Many2one('procurement.group',
                                           'Procurement Group',
                                           copy=False)

    product_id = fields.Many2one('product.product',
                                 related='order_line.product_id',
                                 string='Product')

    @api.multi
    def button_dummy(self):
        return True

    @api.multi
    def unlink(self):
        for order in self:
            if order.state != 'draft':
                raise UserError(_('You can only delete draft quotations!'))
        return super(SaleOrder, self).unlink()

    @api.multi
    def _track_subtype(self, init_values):
        self.ensure_one()
        if 'state' in init_values and self.state == 'sale':
            return 'sale.mt_order_confirmed'
        elif 'state' in init_values and self.state == 'sent':
            return 'sale.mt_order_sent'
        return super(SaleOrder, self)._track_subtype(init_values)

    @api.multi
    @api.onchange('partner_shipping_id')
    def onchange_partner_shipping_id(self):
        """
        Trigger the change of fiscal position when the shipping address is modified.
        """
        fiscal_position = self.env[
            'account.fiscal.position'].get_fiscal_position(
                self.partner_id.id, self.partner_shipping_id.id)
        if fiscal_position:
            self.fiscal_position_id = fiscal_position
        return {}

    @api.multi
    @api.onchange('partner_id')
    def onchange_partner_id(self):
        """
        Update the following fields when the partner is changed:
        - Pricelist
        - Payment term
        - Invoice address
        - Delivery address
        """
        if not self.partner_id:
            self.update({
                'partner_invoice_id': False,
                'partner_shipping_id': False,
                'payment_term_id': False,
                'fiscal_position_id': False,
            })
            return

        addr = self.partner_id.address_get(['delivery', 'invoice'])
        values = {
            'pricelist_id':
            self.partner_id.property_product_pricelist
            and self.partner_id.property_product_pricelist.id or False,
            'payment_term_id':
            self.partner_id.property_payment_term_id
            and self.partner_id.property_payment_term_id.id or False,
            'partner_invoice_id':
            addr['invoice'],
            'partner_shipping_id':
            addr['delivery'],
            'note':
            self.with_context(
                lang=self.partner_id.lang).env.user.company_id.sale_note,
        }

        if self.partner_id.user_id:
            values['user_id'] = self.partner_id.user_id.id
        if self.partner_id.team_id:
            values['team_id'] = self.partner_id.team_id.id
        self.update(values)

    @api.model
    def create(self, vals):
        if vals.get('name', 'New') == 'New':
            vals['name'] = self.env['ir.sequence'].next_by_code(
                'sale.order') or 'New'

        # Makes sure partner_invoice_id', 'partner_shipping_id' and 'pricelist_id' are defined
        if any(f not in vals for f in
               ['partner_invoice_id', 'partner_shipping_id', 'pricelist_id']):
            partner = self.env['res.partner'].browse(vals.get('partner_id'))
            addr = partner.address_get(['delivery', 'invoice'])
            vals['partner_invoice_id'] = vals.setdefault(
                'partner_invoice_id', addr['invoice'])
            vals['partner_shipping_id'] = vals.setdefault(
                'partner_shipping_id', addr['delivery'])
            vals['pricelist_id'] = vals.setdefault(
                'pricelist_id', partner.property_product_pricelist
                and partner.property_product_pricelist.id)
        result = super(SaleOrder, self).create(vals)
        return result

    @api.multi
    def _prepare_invoice(self):
        """
        Prepare the dict of values to create the new invoice for a sales order. This method may be
        overridden to implement custom invoice generation (making sure to call super() to establish
        a clean extension chain).
        """
        self.ensure_one()
        journal_id = self.env['account.invoice'].default_get(['journal_id'
                                                              ])['journal_id']
        if not journal_id:
            raise UserError(
                _('Please define an accounting sale journal for this company.')
            )
        invoice_vals = {
            'name':
            self.client_order_ref or '',
            'origin':
            self.name,
            'type':
            'out_invoice',
            'reference':
            self.client_order_ref or self.name,
            'account_id':
            self.partner_invoice_id.property_account_receivable_id.id,
            'partner_id':
            self.partner_invoice_id.id,
            'journal_id':
            journal_id,
            'currency_id':
            self.pricelist_id.currency_id.id,
            'comment':
            self.note,
            'payment_term_id':
            self.payment_term_id.id,
            'fiscal_position_id':
            self.fiscal_position_id.id
            or self.partner_invoice_id.property_account_position_id.id,
            'company_id':
            self.company_id.id,
            'user_id':
            self.user_id and self.user_id.id,
            'team_id':
            self.team_id.id
        }
        return invoice_vals

    @api.multi
    def print_quotation(self):
        self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'})
        return self.env['report'].get_action(self, 'sale.report_saleorder')

    @api.multi
    def action_view_invoice(self):
        invoice_ids = self.mapped('invoice_ids')
        imd = self.env['ir.model.data']
        action = imd.xmlid_to_object('account.action_invoice_tree1')
        list_view_id = imd.xmlid_to_res_id('account.invoice_tree')
        form_view_id = imd.xmlid_to_res_id('account.invoice_form')

        result = {
            'name':
            action.name,
            'help':
            action.help,
            'type':
            action.type,
            'views': [[list_view_id, 'tree'], [form_view_id, 'form'],
                      [False, 'graph'], [False, 'kanban'], [False, 'calendar'],
                      [False, 'pivot']],
            'target':
            action.target,
            'context':
            action.context,
            'res_model':
            action.res_model,
        }
        if len(invoice_ids) > 1:
            result['domain'] = "[('id','in',%s)]" % invoice_ids.ids
        elif len(invoice_ids) == 1:
            result['views'] = [(form_view_id, 'form')]
            result['res_id'] = invoice_ids.ids[0]
        else:
            result = {'type': 'ir.actions.act_window_close'}
        return result

    @api.multi
    def action_invoice_create(self, grouped=False, final=False):
        """
        Create the invoice associated to the SO.
        :param grouped: if True, invoices are grouped by SO id. If False, invoices are grouped by
                        (partner, currency)
        :param final: if True, refunds will be generated if necessary
        :returns: list of created invoices
        """
        inv_obj = self.env['account.invoice']
        precision = self.env['decimal.precision'].precision_get(
            'Product Unit of Measure')
        invoices = {}

        for order in self:
            group_key = order.id if grouped else (order.partner_id.id,
                                                  order.currency_id.id)
            for line in order.order_line.sorted(
                    key=lambda l: l.qty_to_invoice < 0):
                if float_is_zero(line.qty_to_invoice,
                                 precision_digits=precision):
                    continue
                if group_key not in invoices:
                    inv_data = order._prepare_invoice()
                    invoice = inv_obj.create(inv_data)
                    invoices[group_key] = invoice
                elif group_key in invoices and order.name not in invoices[
                        group_key].origin.split(', '):
                    invoices[group_key].write({
                        'origin':
                        invoices[group_key].origin + ', ' + order.name
                    })
                if line.qty_to_invoice > 0:
                    line.invoice_line_create(invoices[group_key].id,
                                             line.qty_to_invoice)
                elif line.qty_to_invoice < 0 and final:
                    line.invoice_line_create(invoices[group_key].id,
                                             line.qty_to_invoice)

        for invoice in invoices.values():
            # If invoice is negative, do a refund invoice instead
            if invoice.amount_untaxed < 0:
                invoice.type = 'out_refund'
                for line in invoice.invoice_line_ids:
                    line.quantity = -line.quantity
            # Necessary to force computation of taxes. In account_invoice, they are triggered
            # by onchanges, which are not triggered when doing a create.
            invoice.compute_taxes()

        return [inv.id for inv in invoices.values()]

    @api.multi
    def action_draft(self):
        self.filtered(lambda s: s.state in ['cancel', 'sent']).write(
            {'state': 'draft'})

    @api.multi
    def action_cancel(self):
        self.write({'state': 'cancel'})

    @api.multi
    def action_quotation_send(self):
        '''
        This function opens a window to compose an email, with the edi sale template message loaded by default
        '''
        self.ensure_one()
        ir_model_data = self.env['ir.model.data']
        try:
            template_id = ir_model_data.get_object_reference(
                'sale', 'email_template_edi_sale')[1]
        except ValueError:
            template_id = False
        try:
            compose_form_id = ir_model_data.get_object_reference(
                'mail', 'email_compose_message_wizard_form')[1]
        except ValueError:
            compose_form_id = False
        ctx = dict()
        ctx.update({
            'default_model': 'sale.order',
            'default_res_id': self.ids[0],
            'default_use_template': bool(template_id),
            'default_template_id': template_id,
            'default_composition_mode': 'comment',
            'mark_so_as_sent': True
        })
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form_id, 'form')],
            'view_id': compose_form_id,
            'target': 'new',
            'context': ctx,
        }

    @api.multi
    def force_quotation_send(self):
        for order in self:
            email_act = order.action_quotation_send()
            if email_act and email_act.get('context'):
                email_ctx = email_act['context']
                email_ctx.update(default_email_from=order.company_id.email)
                order.with_context(email_ctx).message_post_with_template(
                    email_ctx.get('default_template_id'))
        return True

    @api.multi
    def action_done(self):
        self.write({'state': 'done'})

    @api.model
    def _prepare_procurement_group(self):
        return {'name': self.name}

    @api.multi
    def action_confirm(self):
        for order in self:
            order.state = 'sale'
            if self.env.context.get('send_email'):
                self.force_quotation_send()
            order.order_line._action_procurement_create()
            if not order.project_id:
                for line in order.order_line:
                    if line.product_id.invoice_policy == 'cost':
                        order._create_analytic_account()
                        break
        if self.env['ir.values'].get_default('sale.config.settings',
                                             'auto_done_setting'):
            self.action_done()

    @api.multi
    def _create_analytic_account(self, prefix=None):
        for order in self:
            name = order.name
            if prefix:
                name = prefix + ": " + order.name
            analytic = self.env['account.analytic.account'].create({
                'name':
                name,
                'code':
                order.client_order_ref,
                'company_id':
                order.company_id.id,
                'partner_id':
                order.partner_id.id
            })
            order.project_id = analytic
Esempio n. 22
0
class AccountFinancialReportLine(models.Model):
    _name = "account.financial.html.report.line"
    _description = "Account Report Line"
    _order = "sequence"

    name = fields.Char('Section Name', translate=True)
    code = fields.Char('Code')
    financial_report_id = fields.Many2one('account.financial.html.report',
                                          'Financial Report')
    parent_id = fields.Many2one('account.financial.html.report.line',
                                string='Parent')
    children_ids = fields.One2many('account.financial.html.report.line',
                                   'parent_id',
                                   string='Children')
    sequence = fields.Integer()

    domain = fields.Char(default=None)
    formulas = fields.Char()
    groupby = fields.Char("Group by", default=False)
    figure_type = fields.Selection([('float', 'Float'),
                                    ('percents', 'Percents'),
                                    ('no_unit', 'No Unit')],
                                   'Type',
                                   default='float',
                                   required=True)
    green_on_positive = fields.Boolean('Is growth good when positive',
                                       default=True)
    level = fields.Integer(required=True)
    special_date_changer = fields.Selection(
        [('from_beginning', 'From the beginning'),
         ('to_beginning_of_period', 'At the beginning of the period'),
         ('normal', 'Use given dates'),
         ('strict_range',
          'Force given dates for all accounts and account types')],
        default='normal')
    show_domain = fields.Selection([('always', 'Always'), ('never', 'Never'),
                                    ('foldable', 'Foldable')],
                                   default='foldable')
    hide_if_zero = fields.Boolean(default=False)
    action_id = fields.Many2one('ir.actions.actions')

    @api.one
    @api.constrains('groupby')
    def _check_same_journal(self):
        if self.groupby and self.groupby not in self.env[
                'account.move.line']._columns:
            raise ValidationError("Groupby should be a journal item field")

    def _get_sum(self, field_names=None):
        ''' Returns the sum of the amls in the domain '''
        if not field_names:
            field_names = ['debit', 'credit', 'balance', 'amount_residual']
        res = dict((fn, 0.0) for fn in field_names)
        if self.domain:
            amls = self.env['account.move.line'].search(safe_eval(self.domain))
            compute = amls._compute_fields(field_names)
            for aml in amls:
                if compute.get(aml.id):
                    for field in field_names:
                        res[field] += compute[aml.id][field]
        return res

    @api.one
    def get_balance(self, linesDict, field_names=None):
        if not field_names:
            field_names = ['debit', 'credit', 'balance']
        res = dict((fn, 0.0) for fn in field_names)
        c = FormulaContext(self.env['account.financial.html.report.line'],
                           linesDict, self)
        if self.formulas:
            for f in self.formulas.split(';'):
                [field, formula] = f.split('=')
                field = field.strip()
                if field in field_names:
                    try:
                        res[field] = safe_eval(formula, c, nocopy=True)
                    except ValueError as err:
                        if 'division by zero' in err.args[0]:
                            res[field] = 0
                        else:
                            raise err
        return res

    def _format(self, value):
        if self.env.context.get('no_format'):
            return value
        if self.figure_type == 'float':
            currency_id = self.env.user.company_id.currency_id
            if currency_id.is_zero(value):
                # don't print -0.0 in reports
                value = abs(value)
            return formatLang(self.env, value, currency_obj=currency_id)
        if self.figure_type == 'percents':
            return str(round(value * 100, 1)) + '%'
        return round(value, 1)

    def _get_gb_name(self, gb_id):
        if self.groupby == 'account_id':
            return self.env['account.account'].browse(gb_id).name_get()[0][1]
        if self.groupby == 'user_type_id':
            return self.env['account.account.type'].browse(gb_id).name
        if self.groupby == 'partner_id':
            return self.env['res.partner'].browse(gb_id).name
        return gb_id

    def _build_cmp(self, balance, comp):
        if comp != 0:
            res = round((balance - comp) / comp * 100, 1)
            if (res > 0) != self.green_on_positive:
                return (str(res) + '%', 'color: red;')
            else:
                return (str(res) + '%', 'color: green;')
        else:
            return 'n/a'

    def _split_formulas(self):
        result = {}
        if self.formulas:
            for f in self.formulas.split(';'):
                [column, formula] = f.split('=')
                column = column.strip()
                result.update({column: formula})
        return result

    def _eval_formula(self, financial_report, debit_credit, context,
                      currency_table, linesDict):
        debit_credit = debit_credit and financial_report.debit_credit
        formulas = self._split_formulas()
        if self.code and self.code in linesDict:
            res = linesDict[self.code]
        else:
            res = FormulaLine(self, linesDict=linesDict)
        vals = {}
        vals['balance'] = res.balance
        if debit_credit:
            vals['credit'] = res.credit
            vals['debit'] = res.debit

        results = {}
        if self.domain and self.groupby and self.show_domain != 'never':
            aml_obj = self.env['account.move.line']
            tables, where_clause, where_params = aml_obj._query_get(
                domain=self.domain)
            params = []

            if currency_table.keys():
                groupby = self.groupby or 'id'
                if groupby not in self.env['account.move.line']._columns:
                    raise ValueError(
                        'Groupby should be a field from account.move.line')
                select = ',COALESCE(SUM(CASE '
                for currency_id in currency_table.keys():
                    params += [currency_id, currency_table[currency_id]]
                    select += 'WHEN \"account_move_line\".company_currency_id = %s THEN (\"account_move_line\".debit-\"account_move_line\".credit) * %s '
                select += 'ELSE \"account_move_line\".debit-\"account_move_line\".credit END), 0),SUM(CASE '
                for currency_id in currency_table.keys():
                    params += [currency_id, currency_table[currency_id]]
                    select += 'WHEN \"account_move_line\".company_currency_id = %s THEN \"account_move_line\".amount_residual * %s '
                select += 'ELSE \"account_move_line\".amount_residual END)'
                if financial_report.debit_credit and debit_credit:
                    select += ',SUM(CASE '
                    for currency_id in currency_table.keys():
                        params += [currency_id, currency_table[currency_id]]
                        select += 'WHEN \"account_move_line\".company_currency_id = %s THEN \"account_move_line\".debit * %s '
                    select += 'ELSE \"account_move_line\".debit END),SUM(CASE '
                    for currency_id in currency_table.keys():
                        params += [currency_id, currency_table[currency_id]]
                        select += 'WHEN \"account_move_line\".company_currency_id = %s THEN \"account_move_line\".credit * %s '
                    select += 'ELSE \"account_move_line\".credit END)'
                if self.env.context.get('cash_basis'):
                    select = select.replace('debit',
                                            'debit_cash_basis').replace(
                                                'credit', 'credit_cash_basis')
                sql = "SELECT \"account_move_line\"." + groupby + select + " FROM " + tables + " WHERE " + where_clause + " GROUP BY \"account_move_line\".company_currency_id,\"account_move_line\"." + groupby
            else:
                groupby = self.groupby or 'id'
                select = ',COALESCE(SUM(\"account_move_line\".debit-\"account_move_line\".credit), 0),SUM(\"account_move_line\".amount_residual)'
                if financial_report.debit_credit and debit_credit:
                    select += ',SUM(\"account_move_line\".debit),SUM(\"account_move_line\".credit)'
                if self.env.context.get('cash_basis'):
                    select = select.replace('debit',
                                            'debit_cash_basis').replace(
                                                'credit', 'credit_cash_basis')
                sql = "SELECT \"account_move_line\"." + groupby + select + " FROM " + tables + " WHERE " + where_clause + " GROUP BY \"account_move_line\".company_currency_id,\"account_move_line\"." + groupby

            params += where_params
            self.env.cr.execute(sql, params)
            results = self.env.cr.fetchall()
            if financial_report.debit_credit and debit_credit:
                results = dict([(k[0], {
                    'balance': k[1],
                    'amount_residual': k[2],
                    'debit': k[3],
                    'credit': k[4]
                }) for k in results])
            else:
                results = dict([(k[0], {
                    'balance': k[1],
                    'amount_residual': k[2]
                }) for k in results])
            c = FormulaContext(self.env['account.financial.html.report.line'],
                               linesDict)
            if formulas:
                for key in results:
                    c['sum'] = FormulaLine(results[key], type='not_computed')
                    for col, formula in formulas.items():
                        if col in results[key]:
                            results[key][col] = safe_eval(formula,
                                                          c,
                                                          nocopy=True)
            to_del = []
            for key in results:
                if self.env.user.company_id.currency_id.is_zero(
                        results[key]['balance']):
                    to_del.append(key)
            for key in to_del:
                del results[key]

        results.update({'line': vals})
        return results

    def _put_columns_together(self, data, domain_ids):
        res = dict((domain_id, []) for domain_id in domain_ids)
        for period in data:
            debit_credit = False
            if 'debit' in period['line']:
                debit_credit = True
            for domain_id in domain_ids:
                if debit_credit:
                    res[domain_id].append(
                        period.get(domain_id, {'debit': 0})['debit'])
                    res[domain_id].append(
                        period.get(domain_id, {'credit': 0})['credit'])
                res[domain_id].append(
                    period.get(domain_id, {'balance': 0})['balance'])
        return res

    def _divide_line(self, line):
        line1 = {
            'id': line['id'],
            'name': line['name'],
            'type': 'line',
            'level': line['level'],
            'footnotes': line['footnotes'],
            'columns': [''] * len(line['columns']),
            'unfoldable': line['unfoldable'],
            'unfolded': line['unfolded'],
        }
        line2 = {
            'id':
            line['id'],
            'name':
            _('Total') + ' ' + line['name'],
            'type':
            'total',
            'level':
            line['level'] + 1,
            'footnotes':
            self.env.context['context']._get_footnotes('total', line['id']),
            'columns':
            line['columns'],
            'unfoldable':
            False,
        }
        return [line1, line2]

    @api.multi
    def get_lines(self, financial_report, context, currency_table, linesDicts):
        final_result_table = []
        comparison_table = context.get_periods()
        # build comparison table

        for line in self:
            res = []
            debit_credit = len(comparison_table) == 1
            domain_ids = {'line'}
            k = 0
            for period in comparison_table:
                period_from = period[0]
                period_to = period[1]
                strict_range = False
                if line.special_date_changer == 'from_beginning':
                    period_from = False
                if line.special_date_changer == 'to_beginning_of_period':
                    date_tmp = datetime.strptime(
                        period[0], "%Y-%m-%d") - relativedelta(days=1)
                    period_to = date_tmp.strftime('%Y-%m-%d')
                    period_from = False
                if line.special_date_changer == 'strict_range':
                    strict_range = True
                r = line.with_context(date_from=period_from,
                                      date_to=period_to,
                                      strict_range=strict_range)._eval_formula(
                                          financial_report, debit_credit,
                                          context, currency_table,
                                          linesDicts[k])
                debit_credit = False
                res.append(r)
                domain_ids.update(set(r.keys()))
                k += 1

            res = self._put_columns_together(res, domain_ids)
            if line.hide_if_zero and sum(
                [k == 0 and [True] or [] for k in res['line']], []):
                continue

            # Post-processing ; creating line dictionnary, building comparison, computing total for extended, formatting
            vals = {
                'id':
                line.id,
                'name':
                line.name,
                'type':
                'line',
                'level':
                line.level,
                'footnotes':
                context._get_footnotes('line', line.id),
                'columns':
                res['line'],
                'unfoldable':
                len(domain_ids) > 1 and line.show_domain != 'always',
                'unfolded':
                line in context.unfolded_lines or line.show_domain == 'always',
            }
            if line.action_id:
                vals['action_id'] = line.action_id.id
            domain_ids.remove('line')
            lines = [vals]
            groupby = line.groupby or 'aml'
            if line in context.unfolded_lines or line.show_domain == 'always':
                if line.groupby == 'partner_id' or line.groupby == 'account_id':
                    domain_ids = sorted(list(domain_ids),
                                        key=lambda k: line._get_gb_name(k))
                for domain_id in domain_ids:
                    name = line._get_gb_name(domain_id)
                    vals = {
                        'id': domain_id,
                        'name': name and len(name) >= 45 and name[0:40] + '...'
                        or name,
                        'level': 1,
                        'type': groupby,
                        'footnotes':
                        context._get_footnotes(groupby, domain_id),
                        'columns': res[domain_id],
                    }
                    lines.append(vals)
                if domain_ids:
                    lines.append({
                        'id':
                        line.id,
                        'name':
                        _('Total') + ' ' + line.name,
                        'type':
                        'o_account_reports_domain_total',
                        'level':
                        1,
                        'footnotes':
                        context._get_footnotes(
                            'o_account_reports_domain_total', line.id),
                        'columns':
                        list(lines[0]['columns']),
                    })

            for vals in lines:
                if financial_report.report_type == 'date_range_extended':
                    vals['columns'].append(sum(vals['columns']))
                if len(comparison_table) == 2:
                    vals['columns'].append(
                        line._build_cmp(vals['columns'][0],
                                        vals['columns'][1]))
                    for i in [0, 1]:
                        vals['columns'][i] = line._format(vals['columns'][i])
                else:
                    vals['columns'] = map(line._format, vals['columns'])
                if not line.formulas:
                    vals['columns'] = ['' for k in vals['columns']]

            if len(lines) == 1:
                new_lines = line.children_ids.get_lines(
                    financial_report, context, currency_table, linesDicts)
                if new_lines and line.level > 0 and line.formulas:
                    divided_lines = self._divide_line(lines[0])
                    result = [divided_lines[0]
                              ] + new_lines + [divided_lines[1]]
                else:
                    result = []
                    if line.level > 0:
                        result += lines
                    result += new_lines
                    if line.level <= 0:
                        result += lines
            else:
                result = lines
            final_result_table += result

        return final_result_table
Esempio n. 23
0
class ComunicazioneLiquidazione(models.Model):
    _name = 'comunicazione.liquidazione'
    _description = 'Comunicazione Liquidazione IVA'

    @api.model
    def _default_company(self):
        company_id = self._context.get('company_id',
                                       self.env.user.company_id.id)
        return company_id

    @api.constrains('identificativo')
    def _check_identificativo(self):
        domain = [('identificativo', '=', self.identificativo)]
        dichiarazioni = self.search(domain)
        if len(dichiarazioni) > 1:
            raise ValidationError(
                _("Dichiarazione già esiste con identificativo {}").format(
                    self.identificativo))

    @api.multi
    def _compute_name(self):
        for dich in self:
            name = ""
            for quadro in dich.quadri_vp_ids:
                if not name:
                    period_type = ''
                    if quadro.period_type == 'month':
                        period_type = _('month')
                    else:
                        period_type = _('quarter')
                    name += '{} {}'.format(str(dich.year), period_type)
                if quadro.period_type == 'month':
                    name += ', {}'.format(str(quadro.month))
                else:
                    name += ', {}'.format(str(quadro.quarter))
            dich.name = name

    def _get_identificativo(self):
        dichiarazioni = self.search([])
        if dichiarazioni:
            return len(dichiarazioni) + 1
        else:
            return 1

    company_id = fields.Many2one('res.company',
                                 string='Company',
                                 required=True,
                                 default=_default_company)
    identificativo = fields.Integer(string='Identificativo',
                                    default=_get_identificativo)
    name = fields.Char(string='Name', compute="_compute_name")
    year = fields.Integer(string='Year', required=True, size=4)
    last_month = fields.Integer(string='Last month')
    liquidazione_del_gruppo = fields.Boolean(string='Liquidazione del gruppo')
    taxpayer_vat = fields.Char(string='Vat', required=True)
    controller_vat = fields.Char(string='Controller Vat')
    taxpayer_fiscalcode = fields.Char(string='Fiscalcode')
    declarant_different = fields.Boolean(
        string='Declarant different from taxpayer')
    declarant_fiscalcode = fields.Char(string='Fiscalcode')
    declarant_fiscalcode_company = fields.Char(string='Fiscalcode company')
    codice_carica_id = fields.Many2one('codice.carica', string='Codice carica')
    declarant_sign = fields.Boolean(string='Declarant sign', default=True)

    delegate_fiscalcode = fields.Char(string='Fiscalcode')
    delegate_commitment = fields.Selection(
        [('1', 'Comunicazione è stata predisposta dal contribuente '),
         ('2', 'Comunicazione è stata predisposta da chi effettua l’invio')],
        string='Commitment')
    delegate_sign = fields.Boolean(string='Delegate sign')
    date_commitment = fields.Date(string='Date commitment')
    quadri_vp_ids = fields.One2many('comunicazione.liquidazione.vp',
                                    'comunicazione_id',
                                    string="Quadri VP")
    iva_da_versare = fields.Float(string='IVA da versare', readonly=True)
    iva_a_credito = fields.Float(string='IVA a credito', readonly=True)

    @api.model
    def create(self, vals):
        comunicazione = super(ComunicazioneLiquidazione, self).create(vals)
        comunicazione._validate()
        return comunicazione

    @api.multi
    def write(self, vals):
        super(ComunicazioneLiquidazione, self).write(vals)
        for comunicazione in self:
            comunicazione._validate()
        return True

    @api.onchange('company_id')
    def onchange_company_id(self):
        if self.company_id:
            if self.company_id.partner_id.vat:
                self.taxpayer_vat = self.company_id.partner_id.vat[2:]
            else:
                self.taxpayer_vat = ''
            self.taxpayer_fiscalcode = \
                self.company_id.partner_id.fiscalcode

    def get_export_xml(self):
        self._validate()
        x1_Fornitura = self._export_xml_get_fornitura()

        x1_1_Intestazione = self._export_xml_get_intestazione()

        attrs = {'identificativo': str(self.identificativo).zfill(5)}
        x1_2_Comunicazione = etree.Element(etree.QName(NS_IV, "Comunicazione"),
                                           attrs)
        x1_2_1_Frontespizio = self._export_xml_get_frontespizio()
        x1_2_Comunicazione.append(x1_2_1_Frontespizio)

        x1_2_2_DatiContabili = etree.Element(
            etree.QName(NS_IV, "DatiContabili"))
        nr_modulo = 0
        for quadro in self.quadri_vp_ids:
            nr_modulo += 1
            modulo = self.with_context(nr_modulo=nr_modulo)\
                ._export_xml_get_dati_modulo(quadro)
            x1_2_2_DatiContabili.append(modulo)
        x1_2_Comunicazione.append(x1_2_2_DatiContabili)
        # Composizione struttura xml con le varie sezioni generate
        x1_Fornitura.append(x1_1_Intestazione)
        x1_Fornitura.append(x1_2_Comunicazione)

        xml_string = etree.tostring(x1_Fornitura,
                                    encoding='utf8',
                                    method='xml',
                                    pretty_print=True)
        return xml_string

    def _validate(self):
        """
        Controllo congruità dati della comunicazione
        """
        # Anno obbligatorio
        if not self.year:
            raise ValidationError(_("Year required"))

        # Codice Fiscale
        if not self.taxpayer_fiscalcode \
                or len(self.taxpayer_fiscalcode) not in [11, 16]:
            raise ValidationError(
                _("Taxpayer Fiscalcode is required. It's accepted codes \
                    with lenght 11 or 16 chars"))

        # Codice Fiscale dichiarante Obbligatorio se il codice fiscale
        # del contribuente è di 11 caratteri
        if self.taxpayer_fiscalcode  and len(self.taxpayer_fiscalcode) == 11\
                and not self.declarant_fiscalcode:
            raise ValidationError(
                _("Declarant Fiscalcode is required. You can enable the \
                section with different declarant option"))

        # LiquidazioneGruppo: elemento opzionale, di tipo DatoCB_Type.
        # Se presente non deve essere presente l’elemento PIVAControllante.
        # Non può essere presente se l’elemento CodiceFiscale è lungo 16
        # caratteri.
        if self.liquidazione_del_gruppo:
            if self.controller_vat:
                raise ValidationError(
                    _("Per liquidazione del gruppo, partita iva controllante\
                     deve essere vuota"))
            if len(self.taxpayer_fiscalcode) == 16:
                raise ValidationError(
                    _("Liquidazione del gruppo non valida, visto il codice\
                     fiscale di 16 caratteri"))
        # CodiceCaricaDichiarante
        if self.declarant_fiscalcode:
            if not self.codice_carica_id:
                raise ValidationError(
                    _("Indicare il codice carica del dichiarante"))
        # CodiceFiscaleSocieta:
        # Obbligatori per codice carica 9
        if self.codice_carica_id and self.codice_carica_id.code == '9':
            if not self.declarant_fiscalcode_company:
                raise ValidationError(
                    _("Visto il codice carica, occorre indicare il codice \
                    fiscale della socità dichiarante"))
        # ImpegnoPresentazione::
        if self.delegate_fiscalcode:
            if not self.delegate_commitment:
                raise ValidationError(
                    _("Visto il codice fiscale dell'intermediario, occorre \
                    indicare il codice l'impegno"))
            if not self.date_commitment:
                raise ValidationError(
                    _("Visto il codice fiscale dell'intermediario, occorre \
                    indicare la data dell'impegno"))
        # ImpegnoPresentazione::
        if self.delegate_fiscalcode and not self.delegate_sign:
            raise ValidationError(
                _("In presenza dell'incaricato nella sezione impegno \
                    alla presentazione telematica, è necessario vistare \
                    l'opzione firma dell'incaricato"))
        return True

    def _export_xml_get_fornitura(self):
        x1_Fornitura = etree.Element(etree.QName(NS_IV, "Fornitura"),
                                     nsmap=NS_MAP)
        return x1_Fornitura

    def _export_xml_validate(self):
        return True

    def _export_xml_get_intestazione(self):
        x1_1_Intestazione = etree.Element(etree.QName(NS_IV, "Intestazione"))
        # Codice Fornitura
        x1_1_1_CodiceFornitura = etree.SubElement(
            x1_1_Intestazione, etree.QName(NS_IV, "CodiceFornitura"))
        code = str(self.year)[-2:]
        x1_1_1_CodiceFornitura.text = unicode('IVP{}'.format(code))
        # Codice Fiscale Dichiarante
        if self.declarant_fiscalcode:
            x1_1_2_CodiceFiscaleDichiarante = etree.SubElement(
                x1_1_Intestazione,
                etree.QName(NS_IV, "CodiceFiscaleDichiarante"))
            x1_1_2_CodiceFiscaleDichiarante.text = unicode(
                self.declarant_fiscalcode)
        # Codice Carica
        if self.codice_carica_id:
            x1_1_3_CodiceCarica = etree.SubElement(
                x1_1_Intestazione, etree.QName(NS_IV, "CodiceCarica"))
            x1_1_3_CodiceCarica.text = unicode(self.codice_carica_id.code)
        return x1_1_Intestazione

    def _export_xml_get_frontespizio(self):
        x1_2_1_Frontespizio = etree.Element(etree.QName(NS_IV, "Frontespizio"))
        # Codice Fiscale
        x1_2_1_1_CodiceFiscale = etree.SubElement(
            x1_2_1_Frontespizio, etree.QName(NS_IV, "CodiceFiscale"))
        x1_2_1_1_CodiceFiscale.text = unicode(self.taxpayer_fiscalcode) \
            if self.taxpayer_fiscalcode else ''
        # Anno Imposta
        x1_2_1_2_AnnoImposta = etree.SubElement(
            x1_2_1_Frontespizio, etree.QName(NS_IV, "AnnoImposta"))
        x1_2_1_2_AnnoImposta.text = str(self.year)
        # Partita IVA
        x1_2_1_3_PartitaIVA = etree.SubElement(
            x1_2_1_Frontespizio, etree.QName(NS_IV, "PartitaIVA"))
        x1_2_1_3_PartitaIVA.text = self.taxpayer_vat
        # PIVA Controllante
        if self.controller_vat:
            x1_2_1_4_PIVAControllante = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "PIVAControllante"))
            x1_2_1_4_PIVAControllante.text = self.controller_vat
        # Ultimo Mese
        if self.last_month:
            x1_2_1_5_UltimoMese = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "UltimoMese"))
            x1_2_1_5_UltimoMese.text = self.last_month
        # Liquidazione Gruppo
        x1_2_1_6_LiquidazioneGruppo = etree.SubElement(
            x1_2_1_Frontespizio, etree.QName(NS_IV, "LiquidazioneGruppo"))
        x1_2_1_6_LiquidazioneGruppo.text = \
            '1' if self.liquidazione_del_gruppo else '0'
        # CF Dichiarante
        if self.declarant_fiscalcode:
            x1_2_1_7_CFDichiarante = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "CFDichiarante"))
            x1_2_1_7_CFDichiarante.text = self.declarant_fiscalcode
        # CodiceCaricaDichiarante
        if self.codice_carica_id:
            x1_2_1_8_CodiceCaricaDichiarante = etree.SubElement(
                x1_2_1_Frontespizio,
                etree.QName(NS_IV, "CodiceCaricaDichiarante"))
            x1_2_1_8_CodiceCaricaDichiarante.text = self.codice_carica_id.code
        # CodiceFiscaleSocieta
        if self.declarant_fiscalcode_company:
            x1_2_1_9_CodiceFiscaleSocieta = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV,
                                                 "CodiceFiscaleSocieta"))
            x1_2_1_9_CodiceFiscaleSocieta.text =\
                self.declarant_fiscalcode_company.code
        # FirmaDichiarazione
        x1_2_1_10_FirmaDichiarazione = etree.SubElement(
            x1_2_1_Frontespizio, etree.QName(NS_IV, "FirmaDichiarazione"))
        x1_2_1_10_FirmaDichiarazione.text = '1' if self.declarant_sign else '0'
        # CFIntermediario
        if self.delegate_fiscalcode:
            x1_2_1_11_CFIntermediario = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "CFIntermediario"))
            x1_2_1_11_CFIntermediario.text = self.delegate_fiscalcode
        # ImpegnoPresentazione
        if self.delegate_commitment:
            x1_2_1_12_ImpegnoPresentazione = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV,
                                                 "ImpegnoPresentazione"))
            x1_2_1_12_ImpegnoPresentazione.text = self.delegate_commitment
        # DataImpegno
        if self.date_commitment:
            x1_2_1_13_DataImpegno = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "DataImpegno"))
            x1_2_1_13_DataImpegno.text = datetime.strptime(
                self.date_commitment, "%Y-%m-%d").strftime('%d%m%Y')
        # FirmaIntermediario
        if self.delegate_fiscalcode:
            x1_2_1_14_FirmaIntermediario = etree.SubElement(
                x1_2_1_Frontespizio, etree.QName(NS_IV, "FirmaIntermediario"))
            x1_2_1_14_FirmaIntermediario.text =\
                '1' if self.delegate_sign else '0'

        return x1_2_1_Frontespizio

    def _export_xml_get_dati_modulo(self, quadro):
        # 1.2.2.1 Modulo
        xModulo = etree.Element(etree.QName(NS_IV, "Modulo"))
        # Numero Modulo
        NumeroModulo = etree.SubElement(xModulo,
                                        etree.QName(NS_IV, "NumeroModulo"))
        NumeroModulo.text = str(self._context.get('nr_modulo', 1))

        if quadro.period_type == 'month':
            # 1.2.2.1.1 Mese
            Mese = etree.SubElement(xModulo, etree.QName(NS_IV, "Mese"))
            Mese.text = str(quadro.month)
        else:
            # 1.2.2.1.2 Trimestre
            Trimestre = etree.SubElement(xModulo,
                                         etree.QName(NS_IV, "Trimestre"))
            Trimestre.text = str(quadro.quarter)
        # Da escludere per liquidazione del gruppo
        if not self.liquidazione_del_gruppo:
            # 1.2.2.1.3 Subfornitura
            if quadro.subcontracting:
                Subfornitura = etree.SubElement(
                    xModulo, etree.QName(NS_IV, "Subfornitura"))
                Subfornitura.text = '1' if quadro.subcontracting \
                    else '0'
            # 1.2.2.1.4 EventiEccezionali
            if quadro.exceptional_events:
                EventiEccezionali = etree.SubElement(
                    xModulo, etree.QName(NS_IV, "EventiEccezionali"))
                EventiEccezionali.text = quadro.exceptional_events
            # 1.2.2.1.5 TotaleOperazioniAttive
            TotaleOperazioniAttive = etree.SubElement(
                xModulo, etree.QName(NS_IV, "TotaleOperazioniAttive"))
            TotaleOperazioniAttive.text = "{:.2f}"\
                .format(quadro.imponibile_operazioni_attive).replace('.', ',')
            # 1.2.2.1.6  TotaleOperazioniPassive
            TotaleOperazioniPassive = etree.SubElement(
                xModulo, etree.QName(NS_IV, "TotaleOperazioniPassive"))
            TotaleOperazioniPassive.text = "{:.2f}"\
                .format(quadro.imponibile_operazioni_passive).replace('.', ',')
        # 1.2.2.1.7  IvaEsigibile
        IvaEsigibile = etree.SubElement(xModulo,
                                        etree.QName(NS_IV, "IvaEsigibile"))
        IvaEsigibile.text = "{:.2f}".format(quadro.iva_esigibile)\
            .replace('.', ',')
        # 1.2.2.1.8  IvaDetratta
        IvaDetratta = etree.SubElement(xModulo,
                                       etree.QName(NS_IV, "IvaDetratta"))
        IvaDetratta.text = "{:.2f}".format(quadro.iva_detratta)\
            .replace('.', ',')
        # 1.2.2.1.9  IvaDovuta
        if quadro.iva_dovuta_debito:
            IvaDovuta = etree.SubElement(xModulo,
                                         etree.QName(NS_IV, "IvaDovuta"))
            IvaDovuta.text = "{:.2f}".format(quadro.iva_dovuta_debito)\
                .replace('.', ',')
        # 1.2.2.1.10  IvaCredito
        if quadro.iva_dovuta_credito:
            IvaCredito = etree.SubElement(xModulo,
                                          etree.QName(NS_IV, "IvaCredito"))
            IvaCredito.text = "{:.2f}".format(quadro.iva_dovuta_credito)\
                .replace('.', ',')
        # 1.2.2.1.11 DebitoPrecedente
        DebitoPrecedente = etree.SubElement(
            xModulo, etree.QName(NS_IV, "DebitoPrecedente"))
        DebitoPrecedente.text = "{:.2f}".format(
            quadro.debito_periodo_precedente).replace('.', ',')
        # 1.2.2.1.12 CreditoPeriodoPrecedente
        CreditoPeriodoPrecedente = etree.SubElement(
            xModulo, etree.QName(NS_IV, "CreditoPeriodoPrecedente"))
        CreditoPeriodoPrecedente.text = "{:.2f}".format(
            quadro.credito_periodo_precedente).replace('.', ',')
        # 1.2.2.1.13 CreditoAnnoPrecedente
        CreditoAnnoPrecedente = etree.SubElement(
            xModulo, etree.QName(NS_IV, "CreditoAnnoPrecedente"))
        CreditoAnnoPrecedente.text = "{:.2f}".format(
            quadro.credito_anno_precedente).replace('.', ',')
        # 1.2.2.1.14 VersamentiAutoUE
        VersamentiAutoUE = etree.SubElement(
            xModulo, etree.QName(NS_IV, "VersamentiAutoUE"))
        VersamentiAutoUE.text = "{:.2f}".format(
            quadro.versamento_auto_UE).replace('.', ',')
        # 1.2.2.1.15 CreditiImposta
        CreditiImposta = etree.SubElement(xModulo,
                                          etree.QName(NS_IV, "CreditiImposta"))
        CreditiImposta.text = "{:.2f}".format(quadro.crediti_imposta).replace(
            '.', ',')
        # 1.2.2.1.16 InteressiDovuti
        InteressiDovuti = etree.SubElement(
            xModulo, etree.QName(NS_IV, "InteressiDovuti"))
        InteressiDovuti.text = "{:.2f}".format(
            quadro.interessi_dovuti).replace('.', ',')
        # 1.2.2.1.17 Acconto
        Acconto = etree.SubElement(xModulo, etree.QName(NS_IV, "Acconto"))
        Acconto.text = "{:.2f}".format(quadro.accounto_dovuto).replace(
            '.', ',')
        # 1.2.2.1.18 ImportoDaVersare
        ImportoDaVersare = etree.SubElement(
            xModulo, etree.QName(NS_IV, "ImportoDaVersare"))
        ImportoDaVersare.text = "{:.2f}".format(quadro.iva_da_versare).replace(
            '.', ',')
        # 1.2.2.1.19 ImportoACredito
        ImportoACredito = etree.SubElement(
            xModulo, etree.QName(NS_IV, "ImportoACredito"))
        ImportoACredito.text = "{:.2f}".format(quadro.iva_a_credito).replace(
            '.', ',')

        return xModulo
Esempio n. 24
0
class EdiConfigSystem(models.Model):
    _name = 'edi.config.system'

    name = fields.Char(string="Name", required=True)
    supplier_id = fields.Many2one(comodel_name="res.partner",
                                  string="EDI supplier",
                                  domain=[('supplier', '=', True),
                                          ('is_edi', '=', True)],
                                  required=True)
    parent_supplier_id = fields.Many2one(comodel_name="res.partner",
                                         string="EDI Parent supplier",
                                         domain=[('supplier', '=', True),
                                                 ('is_edi', '=', True)])
    ftp_host = fields.Char(string="FTP Server Host",
                           default='xxx.xxx.xxx.xxx',
                           required=True)
    ftp_port = fields.Char(string="FTP Server Port",
                           default='21',
                           required=True)
    ftp_login = fields.Char(string="FTP Login", required=True)
    ftp_password = fields.Char(string="FTP Password", required=True)
    csv_relative_in_path = fields.Char(
        string="Relative path for IN interfaces", default='/', required=True)
    csv_relative_out_path = fields.Char(
        string="Relative path for OUT interfaces", default='/', required=True)
    po_text_file_pattern = fields.Char(string="Purchase order File pattern",
                                       required=True)
    do_text_file_pattern = fields.Char(string="Delivery order File pattern")
    pricing_text_file_pattern = fields.Char(string="Pricing File pattern")
    customer_code = fields.Char(string="Customer code", required=True)
    constant_file_start = fields.Char(string="Constant file start",
                                      required=True)
    constant_file_end = fields.Char(string="Constant file end", required=True)
    vrp_code = fields.Char(string="VRP Code", required=True)
    mapping_ids = fields.One2many(comodel_name="edi.mapping.lines",
                                  inverse_name="config_id")
    price_mapping_ids = fields.One2many(comodel_name="edi.price.mapping",
                                        inverse_name="price_config_id")
    ble_mapping_ids = fields.One2many(comodel_name="edi.ble.mapping",
                                      inverse_name="ble_config_id")
    delivery_sign = fields.Char(string="Delivery sign")
    days = fields.Integer(string="Frequency check (days)")
    header_code = fields.Char(string="Header code")
    lines_code = fields.Char(string="Lines code")

    @api.one
    @api.constrains('ftp_port')
    def _check_ftp_port(self):
        if not self.ftp_port.isdigit():
            raise ValidationError(_("FTP port must be numeric!"))

    @api.model
    def ftp_connection_open(self, edi_system):
        """Return a new FTP connection with found parameters."""
        _logger.info(
            "Trying to connect to ftp://%s@%s:%s" %
            (edi_system.ftp_login, edi_system.ftp_host, edi_system.ftp_port))
        try:
            ftp = FTP()
            ftp.connect(edi_system.ftp_host)
            if edi_system.ftp_login:
                ftp.login(edi_system.ftp_login, edi_system.ftp_password)
            else:
                ftp.login()
            return ftp
        except Exception, e:
            raise ValidationError(
                _("Error when opening FTP connection:\n %s") % tools.ustr(e))
Esempio n. 25
0
class is_cout_calcul(models.Model):
    _name='is.cout.calcul'
    _order='name desc'

    name               = fields.Datetime('Date', required=True     , readonly=True)
    user_id            = fields.Many2one('res.users', 'Responsable', readonly=True)
    product_id         = fields.Many2one('product.product', 'Article')
    segment_id         = fields.Many2one('is.product.segment', 'Segment')
    is_category_id     = fields.Many2one('is.category', 'Catégorie')
    is_gestionnaire_id = fields.Many2one('is.gestionnaire', 'Gestionnaire')
    multiniveaux       = fields.Boolean('Calcul des coûts multi-niveaux')
    cout_actualise_ids = fields.One2many('is.cout.calcul.actualise', 'cout_calcul_id', u"Historique des côuts actualisés")
    niveau_ids         = fields.One2many('is.cout.calcul.niveau'   , 'cout_calcul_id', u"Niveau des articles dans la nomenclature")
    log_ids            = fields.One2many('is.cout.calcul.log', 'cout_calcul_id', u"Logs")
    state              = fields.Selection([('creation',u'Création'), ('prix_achat', u"Calcul des prix d'achat"),('termine', u"Terminé")], u"État", readonly=True, select=True)

    _defaults = {
        'name': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
        'user_id': lambda self, cr, uid, c: uid,
        'multiniveaux': True,
        'state': 'creation',
    }

    detail_nomenclature=[]
    detail_gamme_ma=[]
    detail_gamme_mo=[]

    detail_gamme_ma_pk=[]
    detail_gamme_mo_pk=[]

    mem_couts={}

    @api.multi
    @api.multi
    def nomenclature(self, cout_calcul_obj, product, niveau, multiniveaux=True):
        cr = self._cr
        type_article=self.type_article(product)
        cout=self.creation_cout(cout_calcul_obj, product, type_article)
        if type_article!='A' and multiniveaux==True:
            if niveau>10:
                raise Warning(u"Trop de niveaux (>10) dans la nomenclature du "+product.is_code)
            SQL="""
                select mbl.product_id, mbl.id, mbl.sequence, mb.id
                from mrp_bom mb inner join mrp_bom_line mbl on mbl.bom_id=mb.id
                                inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id
                where pp.id="""+str(product.id)+ """ 
                order by mbl.sequence, mbl.id
            """
            #TODO : Voir si ce filtre est necessaire : and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null)
            cr.execute(SQL)
            result = cr.fetchall()
            niv=niveau+1
            for row2 in result:
                composant=self.env['product.product'].browse(row2[0])
                self.nomenclature(cout_calcul_obj, composant, niv)


    @api.multi
    def type_article(self, product):
        type_article=""
        for route in product.route_ids:
            if type_article=='F' and route.name=='Buy':
                type_article='ST'
            if type_article=='A' and route.name=='Manufacture':
                type_article='ST'
            if type_article=='' and route.name=='Manufacture':
                type_article='F'
            if type_article=='' and route.name=='Buy':
                type_article='A'
        return type_article


    @api.multi
    def creation_cout(self, cout_calcul_obj, product, type_article, niveau=0):
        product_id=product.id
        #_logger.info('creation_cout : len(mem_couts)='+str(len(self.mem_couts)))
        if product_id in self.mem_couts:
            action='trouvé'
            cout=self.mem_couts[product_id]
        else:
            cout_obj = self.env['is.cout']
            couts=cout_obj.search([('name', '=', product_id)])
            vals={
                'cout_calcul_id': cout_calcul_obj.id,
                'type_article'  : type_article,
                'niveau'        : niveau,
            }
            if len(couts):
                action='write'
                cout=couts[0]
                cout.write(vals)
            else:
                action='create'
                vals['name'] = product_id
                cout=cout_obj.create(vals)
            self.mem_couts[product_id]=cout
        return cout


    @api.multi
    def action_imprimer_couts(self):
        for obj in self:
            tmp=tempfile.mkdtemp()
            os.system('mkdir '+tmp)
            ct=1
            nb=len(obj.cout_actualise_ids)
            for line in obj.cout_actualise_ids:
                couts=self.env['is.cout'].search([('name', '=', line.product_id.id)])
                for cout in couts:
                    path=tmp+"/"+str(ct)+".pdf"
                    ct=ct+1
                    pdf = self.env['report'].get_pdf(cout, 'is_plastigray.report_is_cout')
                    f = open(path,'wb')
                    f.write(pdf)
                    f.close()

            os.system('pdfjoin -o '+tmp+'/merged.pdf '+tmp+'/*.pdf')
            pdf = open(tmp+'/merged.pdf','rb').read()
            os.system('rm '+tmp+'/*.pdf')
            os.system('rmdir '+tmp)

            # ** Recherche si une pièce jointe est déja associèe ***************
            model=self._name
            name='Couts.pdf'
            attachment_obj = self.env['ir.attachment']
            attachments = attachment_obj.search([('res_model','=',model),('res_id','=',obj.id),('name','=',name)])
            # ******************************************************************

            # ** Creation ou modification de la pièce jointe *******************
            vals = {
                'name':        name,
                'datas_fname': name,
                'type':        'binary',
                'res_model':   model,
                'res_id':      obj.id,
                'datas':       pdf.encode('base64'),
            }
            attachment_id=False
            if attachments:
                for attachment in attachments:
                    attachment.write(vals)
                    attachment_id=attachment.id
            else:
                attachment = attachment_obj.create(vals)
                attachment_id=attachment.id
            return {
                'type' : 'ir.actions.act_url',
                'url': '/web/binary/saveas?model=ir.attachment&field=datas&id='+str(attachment_id)+'&filename_field=name',
                'target': 'self',
            }
            #*******************************************************************




    @api.multi
    def _log(self,operation):
        _logger.info(operation)
        for obj in self:
            vals={
                'cout_calcul_id': obj.id,
                'date'          : datetime.datetime.now(),
                'operation'     : operation,
            }
            res=self.env['is.cout.calcul.log'].create(vals)




#    @api.multi
#    def action_calcul_prix_achat(self):
#        cr = self._cr
#        debut=datetime.datetime.now()
#        for obj in self:
#            #obj.log_ids.unlink()
#            self._log("## DEBUT Calcul des prix d'achat")
#            _logger.info('début unlink')
#            for row in obj.cout_actualise_ids:
#                row.unlink()
#            _logger.info('fin unlink')
#            calcul_actualise_obj = self.env['is.cout.calcul.actualise']
#            _logger.info("début get_products")
#            products=self.get_products(obj)
#            _logger.info("fin get_products : nb="+str(len(products)))



#            #TODO : 0.07s par article (88s pour 1233 articles)
#            ct=1
#            nb=len(products)
#            #print _now(debut), "## début boucle products : nb=",nb

#            _logger.info("début boucle products : nb="+str(nb))

#            for product in products:
#                _logger.info(str(ct)+'/'+str(nb)+' : boucle products : '+product.is_code)
#                #print _now(debut), product,ct,'/',nb
#                ct+=1
#                self.nomenclature(obj,product,0, obj.multiniveaux)
#            couts=self.env['is.cout'].search([('cout_calcul_id', '=', obj.id)])
#            product_uom_obj = self.env['product.uom']
#            #print _now(debut), "## fin boucle products"
#            _logger.info("fin boucle products")




#            ct=1
#            nb=len(couts)
#            #print _now(debut), "## début boucle couts : nb=",nb
#            _logger.info("début boucle couts : nb="+str(nb))
#            for cout in couts:
#                product=cout.name

#                _logger.info(str(ct)+'/'+str(nb)+' : boucle couts : '+product.is_code)

#                #print _now(debut), product.is_code,ct,'/',nb
#                ct+=1


#                prix_tarif    = 0
#                prix_commande = 0
#                prix_facture  = 0
#                prix_calcule  = 0
#                ecart_calcule_matiere = 0
#                vals={
#                    'cout_calcul_id': obj.id,
#                    'product_id': product.id,
#                }
#                res=calcul_actualise_obj.create(vals)
#                type_article=cout.type_article

#                if type_article!='F':
#                    #** Recherche du fournisseur par défaut ********************
#                    seller=False
#                    if len(product.seller_ids)>0:
#                        seller=product.seller_ids[0]
#                    pricelist=False
#                    if seller:
#                        partner=seller.name
#                        pricelist=partner.property_product_pricelist_purchase
#                    #***********************************************************


#                    #** Recherche du prix d'achat ******************************
#                    date=time.strftime('%Y-%m-%d') # Date du jour

#                    if pricelist:
#                        #Convertion du lot_mini de US vers UA
#                        min_quantity = product_uom_obj._compute_qty(cout.name.uom_id.id, cout.name.lot_mini, cout.name.uom_po_id.id)

#                        #TODO : Pour contourner un bug d'arrondi (le 31/01/2017)
#                        min_quantity=min_quantity+0.00000000001
#                        #TODO en utilisant la fonction repr à la place de str, cela ne tronque pas les décimales

#                        SQL="""
#                            select ppi.price_surcharge
#                            from product_pricelist_version ppv inner join product_pricelist_item ppi on ppv.id=ppi.price_version_id
#                            where ppv.pricelist_id="""+str(pricelist.id)+ """ 
#                                  and min_quantity<="""+repr(min_quantity)+"""
#                                  and (ppv.date_start <= '"""+date+"""' or ppv.date_start is null)
#                                  and (ppv.date_end   >= '"""+date+"""' or ppv.date_end   is null)

#                                  and ppi.product_id="""+str(product.id)+ """ 
#                                  and (ppi.date_start <= '"""+date+"""' or ppi.date_start is null)
#                                  and (ppi.date_end   >= '"""+date+"""' or ppi.date_end   is null)
#                            order by ppi.sequence
#                            limit 1
#                        """
#                        cr.execute(SQL)
#                        result = cr.fetchall()
#                        for row in result:
#                            #coef=product.uom_po_id.factor_inv
#                            coef=1
#                            if min_quantity:
#                                coef=cout.name.lot_mini/min_quantity
#                            prix_tarif=row[0]/coef
#                    #***********************************************************


#                    #** Recherche prix dernière commande ***********************
#                    SQL="""
#                        select pol.price_unit*pu.factor
#                        from purchase_order_line pol inner join product_uom pu on pol.product_uom=pu.id
#                        where pol.product_id="""+str(product.id)+ """ 
#                              and state in('confirmed','done')
#                        order by pol.id desc limit 1
#                    """
#                    cr.execute(SQL)
#                    result = cr.fetchall()
#                    for row in result:
#                        prix_commande=row[0]
#                    #***********************************************************

#                    #** Recherche prix dernière facture ************************
#                    SQL="""
#                        select ail.price_unit*pu.factor
#                        from account_invoice_line ail inner join product_uom pu on ail.uos_id=pu.id
#                                                      inner join account_invoice ai on ail.invoice_id=ai.id
#                        where ail.product_id="""+str(product.id)+ """ 
#                              and ai.state in('open','paid') and ai.type='in_invoice'
#                        order by ail.id desc limit 1
#                    """
#                    cr.execute(SQL)
#                    result = cr.fetchall()
#                    for row in result:
#                        prix_facture=row[0]
#                    #***********************************************************


#                    if cout.prix_force:
#                        prix_calcule=cout.prix_force
#                    else:
#                        if prix_facture:
#                            prix_calcule=prix_facture
#                        else:
#                            if prix_commande:
#                                prix_calcule=prix_commande
#                            else:
#                                if prix_tarif:
#                                    prix_calcule=prix_tarif



#                    if type_article=='A':
#                        if prix_calcule==0:
#                            prix_calcule=cout.cout_act_matiere
#                        ecart_calcule_matiere  = prix_calcule - cout.cout_act_matiere
#                    if type_article=='ST':
#                        if prix_calcule==0:
#                            prix_calcule=cout.cout_act_st
#                        ecart_calcule_matiere  = prix_calcule - cout.cout_act_st

#                if prix_tarif:
#                    cout.prix_tarif=prix_tarif


#                cout.type_article  = type_article

#                cout.prix_commande = prix_commande
#                cout.prix_facture  = prix_facture
#                cout.prix_calcule  = prix_calcule
#                cout.ecart_calcule_matiere = ecart_calcule_matiere


#            obj.state="prix_achat"

#        self._log("## FIN Calcul des prix d'achat"+_now(debut))

    @api.multi
    def get_products(self,obj):
        cats=self.env['is.category']._calcul_cout()
        products={}
        if obj.product_id:
            products=self.env['product.product'].search([('id', '=', obj.product_id.id), ('is_category_id', 'in', cats)])
        else:
            if obj.segment_id:
                products=self.env['product.product'].search([('segment_id', '=', obj.segment_id.id), ('is_category_id', 'in', cats)], limit=10000)
            else:
                if obj.is_category_id:
                    products=self.env['product.product'].search([('is_category_id', '=', obj.is_category_id.id)], limit=10000)
                else:
                    if obj.is_gestionnaire_id:
                        products=self.env['product.product'].search([('is_gestionnaire_id', '=', obj.is_gestionnaire_id.id), ('is_category_id', 'in', cats)], limit=10000)
                    else:
                        products=self.env['product.product'].search([('is_category_id', 'in', cats)])
        return products



    @api.multi
    def nomenclature_prix_revient(self, cout_calcul_obj, niveau, product, unite=False, quantite_unitaire=1, quantite_total=1, prix_calcule=0):
        cr = self._cr
        type_article=self.type_article(product)
        cout_mat = 0
        cout_st  = 0
        msg_err=''
        if product.is_category_id.name!='80':
            if type_article=='A':
                cout_mat = prix_calcule
                if prix_calcule==0:
                    msg_err=u'Err Coût Mat'
            if type_article=='ST':
                cout_st  = prix_calcule
                if prix_calcule==0:
                    msg_err=u'Err Coût ST'

        cout=self.creation_cout(cout_calcul_obj, product, type_article)



        self.detail_nomenclature.append({
            'product_id'  : product.id,
            'is_code'     : product.is_code,
            'composant'   : '----------'[:niveau]+str(product.is_code),
            'designation' : product.name,
            'unite'       : unite,
            'quantite'    : quantite_unitaire, 
            'cout_mat'    : cout_mat, 
            'total_mat'   : quantite_total*cout_mat,
            'cout_st'     : cout_st, 
            'total_st'    : quantite_total*cout_st,
            'msg_err'     : msg_err,
        })

        if type_article!='A':
            lot_mini=product.lot_mini
            if lot_mini==0:
                lot_mini=1

            #** Recherche de la gamme ******************************************
            SQL="""
                select mb.routing_id
                from mrp_bom mb inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id
                where pp.id="""+str(product.id)+ """ 
                      and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null)
                order by mb.id
            """
            cr.execute(SQL)
            result = cr.fetchall()
            for row2 in result:
                routing_id = row2[0]
                if routing_id:
                    routing = self.env['mrp.routing'].browse(routing_id)
                    for line in routing.workcenter_lines:
                        cout_total=quantite_unitaire*line.workcenter_id.costs_hour*round(line.is_nb_secondes/3600,4)
                        vals={
                            'composant'     : '----------'[:niveau]+product.is_code,
                            'sequence'      : line.sequence,
                            'workcenter_id' : line.workcenter_id.id,
                            'quantite'      : quantite_unitaire,
                            'cout_prepa'    : line.workcenter_id.costs_hour,
                            'tps_prepa'     : line.workcenter_id.time_start, 
                            'cout_fab'      : line.workcenter_id.costs_hour, 
                            'tps_fab'       : line.is_nb_secondes,
                            'cout_total'    : cout_total, 
                        }
                        if line.workcenter_id.resource_type=='material':
                            self.detail_gamme_ma.append(vals)
                        else:
                            self.detail_gamme_mo.append(vals)




            #** Recherche de la gamme générique pour Cout Plasti-ka ************
            SQL="""
                select mb.is_gamme_generique_id
                from mrp_bom mb inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id
                where pp.id="""+str(product.id)+ """ 
                order by mb.id
            """
            cr.execute(SQL)
            result = cr.fetchall()
            for row2 in result:
                routing_id = row2[0]
                if routing_id:
                    routing = self.env['mrp.routing'].browse(routing_id)
                    for line in routing.workcenter_lines:
                        cout_total=quantite_unitaire*line.workcenter_id.is_cout_pk*round(line.is_nb_secondes/3600,4)
                        vals={
                            'composant'     : '----------'[:niveau]+product.is_code,
                            'sequence'      : line.sequence,
                            'workcenter_id' : line.workcenter_id.id,
                            'quantite'      : quantite_unitaire,
                            'cout_prepa'    : line.workcenter_id.is_cout_pk,
                            'tps_prepa'     : line.workcenter_id.time_start, 
                            'cout_fab'      : line.workcenter_id.is_cout_pk, 
                            'tps_fab'       : line.is_nb_secondes,
                            'cout_total'    : cout_total, 
                        }
                        if line.workcenter_id.resource_type=='material':
                            self.detail_gamme_ma_pk.append(vals)
                        else:
                            self.detail_gamme_mo_pk.append(vals)
            #*******************************************************************

            #** Composants de la nomenclature **********************************
            SQL="""
                select mbl.product_id, mbl.product_uom, mbl.product_qty, ic.prix_calcule
                from mrp_bom mb inner join mrp_bom_line mbl on mbl.bom_id=mb.id
                                inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id
                                inner join is_cout ic on ic.name=mbl.product_id
                where pp.id="""+str(product.id)+ """ 
                order by mbl.sequence, mbl.id
            """
            # TODO : Filtre sur ce critère ? => and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null)
            cr.execute(SQL)
            result = cr.fetchall()
            niv=niveau+1
            for row2 in result:
                composant    = self.env['product.product'].browse(row2[0])
                unite        = row2[1]
                qt_unitaire  = row2[2]
                qt_total     = qt_unitaire*quantite_total
                prix_calcule = row2[3]
                self.nomenclature_prix_revient(cout_calcul_obj, niv, composant, unite, qt_unitaire, qt_total, prix_calcule)
            #*******************************************************************







    @api.multi
    def _productid2cout(self,product_id):
        cout_obj = self.env['is.cout']
        couts=cout_obj.search([('name', '=', product_id)])
        return couts


    @api.multi
    def _get_couts(self):
        couts=[]
        for obj in self:
            for row in obj.cout_actualise_ids:
                product=row.product_id
                res=self._productid2cout(product.id)
                for r in res:
                    couts.append(r)
        return couts


    @api.multi
    def _unlink_detail_cout(self,couts):
        """En regroupant la suppression de toutes les lignes, cela permet de gagner beaucoup de temps"""
        cr = self._cr
        if couts:
            ids = self._get_couts_ids(couts)
            if ids:
                ids=','.join(ids)
                SQL=''
                SQL+='DELETE FROM is_cout_nomenclature WHERE cout_id in('+ids+'); '
                SQL+='DELETE FROM is_cout_gamme_ma     WHERE cout_id in('+ids+'); '
                SQL+='DELETE FROM is_cout_gamme_mo     WHERE cout_id in('+ids+'); '
                SQL+='DELETE FROM is_cout_gamme_ma_pk  WHERE cout_id in('+ids+'); '
                SQL+='DELETE FROM is_cout_gamme_mo_pk  WHERE cout_id in('+ids+'); '
                cr.execute(SQL)


    @api.multi
    def _get_couts_ids(self,couts):
        """Retourne la liste des id des couts à partir des couts"""
        ids=[]
        for cout in couts:
            ids.append(str(cout.id))
        return ids


    @api.multi
    def _write_resultats(self):
        "Ecrit les résultats des calculs dans la page récapitulative"
        for obj in self:
            for row in obj.cout_actualise_ids:
                product=row.product_id
                couts=self._productid2cout(product.id)
                for cout in couts:
                    vals={}
                    vals['cout_act_matiere']     = cout.cout_act_matiere
                    vals['cout_act_machine']     = cout.cout_act_machine
                    vals['cout_act_mo']          = cout.cout_act_mo
                    vals['cout_act_st']          = cout.cout_act_st
                    vals['cout_act_total']       = cout.cout_act_total
                    row.write(vals)


    @api.multi
    def action_calcul_prix_revient(self):
        #pr=cProfile.Profile()
        #pr.enable()
        for obj in self:
            self._log("## DEBUT Calcul des prix de revient")
            nb=len(obj.cout_actualise_ids)
            ct=0
            couts = self._get_couts()
            self._unlink_detail_cout(couts)
            for cout in couts:



                product=cout.name
                ct=ct+1
                _logger.info(str(ct)+'/'+str(nb)+' : '+str(product.is_code))

                cout_act_matiere    = 0
                cout_act_st         = 0
                cout_act_condition  = 0
                cout_act_machine    = 0
                cout_act_machine_pk = 0
                cout_act_mo         = 0
                cout_act_mo_pk      = 0
                cout_act_total      = 0

                if cout.type_article=='A':
                    cout_act_matiere = cout.prix_calcule
                    cout_act_st      = 0
                if cout.type_article=='ST':
                    cout_act_matiere = 0
                    cout_act_st      = 0

                nb_err=0
                if cout.type_article!='A':
                    self.detail_nomenclature=[]
                    self.detail_gamme_ma=[]
                    self.detail_gamme_mo=[]
                    self.detail_gamme_ma_pk=[]
                    self.detail_gamme_mo_pk=[]

                    self.nomenclature_prix_revient(obj, 0, product, False, 1, 1, cout.prix_calcule)
                    for vals in self.detail_nomenclature:
                        if vals['msg_err']!='':
                            nb_err=nb_err+1
                        is_code=vals['is_code']
                        if is_code[:1]=="7":
                            cout_act_condition=cout_act_condition+vals['total_mat']
                        del vals['is_code']
                        vals['cout_id']=cout.id
                        cout_act_matiere = cout_act_matiere+vals['total_mat']



                        cout_act_st      = cout_act_st+vals['total_st']




                        res=self.env['is.cout.nomenclature'].create(vals)
                    vals={
                        'cout_id'     : cout.id,
                        'designation' : 'TOTAL  : ',
                        'total_mat'   : cout_act_matiere,
                        'total_st'    : cout_act_st,
                    }
                    res=self.env['is.cout.nomenclature'].create(vals)
                    vals={
                        'cout_id'     : cout.id,
                        'designation' : 'Conditionnement  : ',
                        'total_mat'   : cout_act_condition,
                    }
                    res=self.env['is.cout.nomenclature'].create(vals)

                    for vals in self.detail_gamme_ma:
                        vals['cout_id']=cout.id
                        res=self.env['is.cout.gamme.ma'].create(vals)
                        cout_act_machine = cout_act_machine+vals['cout_total']
                    for vals in self.detail_gamme_mo:
                        vals['cout_id']=cout.id
                        res=self.env['is.cout.gamme.mo'].create(vals)
                        cout_act_mo = cout_act_mo+vals['cout_total']

                    for vals in self.detail_gamme_ma_pk:
                        vals['cout_id']=cout.id
                        res=self.env['is.cout.gamme.ma.pk'].create(vals)
                        cout_act_machine_pk = cout_act_machine_pk+vals['cout_total']
                    for vals in self.detail_gamme_mo_pk:
                        vals['cout_id']=cout.id
                        res=self.env['is.cout.gamme.mo.pk'].create(vals)
                        cout_act_mo_pk = cout_act_mo_pk+vals['cout_total']

                vals={}
                #Client par défaut
                for row in product.is_client_ids:
                    if row.client_defaut:
                        vals['partner_id']=row.client_id.id
                vals['nb_err'] = nb_err
                if nb_err>0:
                    cout_act_matiere=0
                cout_act_total=cout_act_matiere+cout_act_machine+cout_act_mo+cout_act_st
                vals['cout_act_matiere']    = cout_act_matiere
                vals['cout_act_condition']  = cout_act_condition
                vals['cout_act_machine']    = cout_act_machine
                vals['cout_act_mo']         = cout_act_mo
                vals['cout_act_machine_pk'] = cout_act_machine_pk
                vals['cout_act_mo_pk']      = cout_act_mo_pk
                vals['cout_act_st']         = cout_act_st
                vals['cout_act_total']      = cout_act_total
                vals['is_category_id']      = product.is_category_id.id
                vals['is_gestionnaire_id']  = product.is_gestionnaire_id.id
                vals['is_mold_id']          = product.is_mold_id.id
                vals['is_mold_dossierf']    = product.is_mold_dossierf
                vals['uom_id']              = product.uom_id.id
                vals['lot_mini']            = product.lot_mini
                vals['cout_act_prix_vente'] = cout.prix_vente-cout.amortissement_moule-cout.surcout_pre_serie
                cout.write(vals)
            self._write_resultats()
            obj.state="termine"
            self._log("## FIN Calcul des prix de revient")
Esempio n. 26
0
class LunchOrderLine(models.Model):
    _name = 'lunch.order.line'
    _description = 'lunch order line'

    name = fields.Char(related='product_id.name', string="Product Name", readonly=True)
    order_id = fields.Many2one('lunch.order', 'Order', ondelete='cascade', required=True)
    product_id = fields.Many2one('lunch.product', 'Product', required=True)
    category_id = fields.Many2one('lunch.product.category', string='Product Category',
                                  related='product_id.category_id', readonly=True, store=True)
    date = fields.Date(string='Date', related='order_id.date', readonly=True, store=True)
    supplier = fields.Many2one('res.partner', string='Vendor', related='product_id.supplier',
                               readonly=True, store=True)
    user_id = fields.Many2one('res.users', string='User', related='order_id.user_id',
                              readonly=True, store=True)
    note = fields.Text('Note')
    price = fields.Float(related='product_id.price', readonly=True, store=True,
                         digits=dp.get_precision('Account'))
    state = fields.Selection([('new', 'New'),
                              ('confirmed', 'Received'),
                              ('ordered', 'Ordered'),
                              ('cancelled', 'Cancelled')],
                             'Status', readonly=True, select=True, default='new')
    cashmove = fields.One2many('lunch.cashmove', 'order_id', 'Cash Move')
    currency_id = fields.Many2one('res.currency', related='order_id.currency_id')

    @api.one
    def order(self):
        """
        The order_line is ordered to the vendor but isn't received yet
        """
        if self.user_has_groups("lunch.group_lunch_manager"):
            self.state = 'ordered'
        else:
            raise AccessError(_("Only your lunch manager processes the orders."))

    @api.one
    def confirm(self):
        """
        confirm one or more order line, update order status and create new cashmove
        """
        if self.user_has_groups("lunch.group_lunch_manager"):
            if self.state != 'confirmed':
                values = {
                    'user_id': self.user_id.id,
                    'amount': -self.price,
                    'description': self.product_id.name,
                    'order_id': self.id,
                    'state': 'order',
                    'date': self.date,
                }
            self.env['lunch.cashmove'].create(values)
            self.state = 'confirmed'
        else:
            raise AccessError(_("Only your lunch manager sets the orders as received."))

    @api.one
    def cancel(self):
        """
        cancel one or more order.line, update order status and unlink existing cashmoves
        """
        if self.user_has_groups("lunch.group_lunch_manager"):
            self.state = 'cancelled'
            self.cashmove.unlink()
        else:
            raise AccessError(_("Only your lunch manager cancels the orders."))
Esempio n. 27
0
class product_wizard(models.TransientModel):
    _name = 'product.batch_list'

    def compute_default_value(self):
        return self.env[self.env.context.get('active_model')].browse(
            self.env.context.get('active_id'))

    product_id = fields.Many2one(comodel_name='product.product',
                                 string='Product',
                                 default=compute_default_value)
    quant_ids = fields.One2many(comodel_name='product.batch_list_quant',
                                string='Quants',
                                inverse_name='batch_list_id')
    location_id = fields.Many2one(
        comodel_name='stock.location'
    )  # domain|context|ondelete="'set null', 'restrict', 'cascade'"|auto_join|delegate
    lot_id = fields.Many2one(comodel_name='stock.production.lot')

    @api.onchange('location_id')
    def onchange_location_id(self):
        # ~ raise Warning(self.env.context)
        domain = [('product_id', '=', self.product_id.id)]
        if self.location_id:
            domain.append(('location_id', 'child_of', self.location_id.id))
        if self.lot_id:
            domain.append(('lot_id', '=', self.lot_id.id))
        quants = self.env['stock.quant'].search(domain)
        quant_ids = []
        if self.quant_ids:
            self.quant_ids.append((5, ))
        for quant in quants:
            quant_ids.append((0, 0, {
                'name': quant.name,
                'qty': quant.qty,
                'lot_id': quant.lot_id.id,
                'removal_date': quant.removal_date,
                'quant_id': quant.id
            }))
        self.quant_ids = quant_ids
        self.product_id = self.env['product.product'].browse(
            self.env.context.get('active_id'))

    def choose_batch(self):
        for quant in self.quant_ids:
            quant.quant_id.sudo().write({
                'lot_id': quant.lot_id.id,
                'qty': quant.qty
            })

    @api.multi
    def empty_location_id(self, *args):
        location = self.env['stock.location'].search([('name', '=', 'Scrapped')
                                                      ])[0]

        _logger.warn("stock_batch location %s" % location)
        move = self.env['stock.move'].create({
            'name':
            _('SCRAP:') + self.product_id.display_name,
            'product_id':
            self.product_id.id,
            'product_uom':
            self.product_id.uom_id.id,
            'product_uom_qty':
            sum([q.qty for q in self.quant_ids.mapped('quant_id')]),
            'date':
            fields.Datetime.now(),
            'company_id':
            self.env.user.company_id.id,
            'state':
            'confirmed',
            'location_id':
            self.location_id.id,
            'location_dest_id':
            location.id,
        })
        # ~ self.env['stock.quant'].quants_move([(q, q.qty) for q in self.quant_ids.mapped('quant_id')], None, location)
        move.action_done()
Esempio n. 28
0
class LunchOrder(models.Model):
    """
    A lunch order contains one or more lunch order line(s). It is associated to a user for a given
    date. When creating a lunch order, applicable lunch alerts are displayed.
    """
    _name = 'lunch.order'
    _description = 'Lunch Order'
    _order = 'date desc'

    def _default_previous_order_ids(self):
        prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid), ('product_id.active', '!=', False)], limit=20, order='id desc')
        # If we return return prev_order.ids, we will have duplicates (identical orders).
        # Therefore, this following part removes duplicates based on product_id and note.
        return {
            (order.product_id, order.note): order.id
            for order in prev_order
        }.values()

    user_id = fields.Many2one('res.users', 'User', required=True, readonly=True,
                              states={'new': [('readonly', False)]},
                              default=lambda self: self.env.uid)
    date = fields.Date('Date', required=True, readonly=True,
                       states={'new': [('readonly', False)]},
                       default=fields.Date.context_today)
    order_line_ids = fields.One2many('lunch.order.line', 'order_id', 'Products',
                                     ondelete="cascade", readonly=True, copy=True,
                                     states={'new': [('readonly', False)], False: [('readonly', False)]})
    total = fields.Float(compute='_compute_total', string="Total", store=True)
    state = fields.Selection([('new', 'New'),
                              ('confirmed', 'Received'),
                              ('cancelled', 'Cancelled')],
                             'Status', readonly=True, index=True, copy=False, default='new',
                             compute='_compute_order_state', store=True)
    alerts = fields.Text(compute='_compute_alerts_get', string="Alerts")
    previous_order_ids = fields.Many2many('lunch.order.line', compute='_compute_previous_order_ids',
                                          default=lambda self: self._default_previous_order_ids())
    company_id = fields.Many2one('res.company', related='user_id.company_id', store=True)
    currency_id = fields.Many2one('res.currency', related='company_id.currency_id', readonly=True, store=True)
    cash_move_balance = fields.Monetary(compute='_compute_cash_move_balance', multi='cash_move_balance')
    balance_visible = fields.Boolean(compute='_compute_cash_move_balance', multi='cash_move_balance')

    @api.one
    @api.depends('order_line_ids')
    def _compute_total(self):
        """
        get and sum the order lines' price
        """
        self.total = sum(
            orderline.price for orderline in self.order_line_ids)

    @api.multi
    def name_get(self):
        return [(order.id, '%s %s' % (_('Lunch Order'), '#%d' % order.id)) for order in self]

    @api.depends('state')
    def _compute_alerts_get(self):
        """
        get the alerts to display on the order form
        """
        alert_msg = [alert.message
                     for alert in self.env['lunch.alert'].search([])
                     if alert.display]

        if self.state == 'new':
            self.alerts = alert_msg and '\n'.join(alert_msg) or False

    @api.depends('user_id')
    def _compute_previous_order_ids(self):
        self.previous_order_ids = self._default_previous_order_ids()

    @api.one
    @api.depends('user_id')
    def _compute_cash_move_balance(self):
        domain = [('user_id', '=', self.user_id.id)]
        lunch_cash = self.env['lunch.cashmove'].read_group(domain, ['amount', 'user_id'], ['user_id'])
        if len(lunch_cash):
            self.cash_move_balance = lunch_cash[0]['amount']
        self.balance_visible = (self.user_id == self.env.user) or self.user_has_groups('lunch.group_lunch_manager')

    @api.one
    @api.constrains('date')
    def _check_date(self):
        """
        Prevents the user to create an order in the past
        """
        date_order = datetime.datetime.strptime(self.date, '%Y-%m-%d')
        date_today = datetime.datetime.strptime(fields.Date.context_today(self), '%Y-%m-%d')
        if (date_order < date_today):
            raise ValidationError(_('The date of your order is in the past.'))

    @api.one
    @api.depends('order_line_ids.state')
    def _compute_order_state(self):
        """
        Update the state of lunch.order based on its orderlines. Here is the logic:
        - if at least one order line is cancelled, the order is set as cancelled
        - if no line is cancelled but at least one line is not confirmed, the order is set as new
        - if all lines are confirmed, the order is set as confirmed
        """
        if not self.order_line_ids:
            self.state = 'new'
        else:
            isConfirmed = True
            for orderline in self.order_line_ids:
                if orderline.state == 'cancelled':
                    self.state = 'cancelled'
                    return
                elif orderline.state == 'confirmed':
                    continue
                else:
                    isConfirmed = False

            if isConfirmed:
                self.state = 'confirmed'
            else:
                self.state = 'new'
        return
Esempio n. 29
0
class AccountMove(models.Model):
    _inherit = 'account.move'

    document = fields.Char(
        string='Document',
        compute='_compute_document',
        store=True,
        readonly=True,
    )
    document_id = fields.Reference(
        REFERENCE_SELECT,
        string='Document',
        compute='_compute_document',
        store=True,
        readonly=True,
    )
    doctype = fields.Selection(
        DOCTYPE_SELECT,
        string='Doctype',
        compute='_compute_document',
        store=True,
        index=True,
        help="Use selection as refer_type in res_doctype",
    )
    date_value = fields.Date(
        string='Value Date',
        compute='_compute_document',
        store=True,
        help="If origin document have value date. Otherwise, use move date",
    )
    invoice_ids = fields.One2many(
        'account.invoice',
        'move_id',
        string='Invoice',
        readonly=True,
    )
    invoice_cancel_ids = fields.One2many(
        'account.invoice',
        'cancel_move_id',
        string='Invoice Cancel',
        readonly=True,
    )
    invoice_clear_prepaid_ids = fields.One2many(
        'account.invoice',
        'clear_prepaid_move_id',
        string='Invoice Clear Prepaid',
        readonly=True,
    )
    voucher_ids = fields.One2many(
        'account.voucher',
        'move_id',
        string='Payment',
        readonly=True,
    )
    voucher_cancel_ids = fields.One2many(
        'account.voucher',
        'cancel_move_id',
        string='Payment Cancel',
        readonly=True,
    )
    voucher_recognize_vat_ids = fields.One2many(
        'account.voucher',
        'recognize_vat_move_id',
        string='Payment Recognize VAT',
        readonly=True,
    )
    bank_receipt_ids = fields.One2many(
        'account.bank.receipt',
        'move_id',
        string='Bank Receipt',
        readonly=True,
    )
    bank_receipt_cancel_ids = fields.One2many(
        'account.bank.receipt',
        'cancel_move_id',
        string='Bank Receipt Cancel',
        readonly=True,
    )
    salary_expense_ids = fields.One2many(
        'hr.salary.expense',
        'move_id',
        string='Salary Expense',
        readonly=True,
    )
    salary_expense_cancel_ids = fields.One2many(
        'hr.salary.expense',
        'cancel_move_id',
        string='Salary Expense Cancel',
        readonly=True,
    )
    expense_rev_ic_ids = fields.One2many(
        'hr.expense.expense',
        'rev_ic_move_id',
        string='IC Revenue',
        readonly=True,
    )
    expense_exp_ic_ids = fields.One2many(
        'hr.expense.expense',
        'exp_ic_move_id',
        string='IC Expense',
        readonly=True,
    )
    account_interface_ids = fields.One2many(
        'interface.account.entry',
        'move_id',
        string='Account Interface',
        readonly=True,
    )

    @api.multi
    @api.depends('invoice_ids.internal_number',
                 'invoice_cancel_ids.internal_number',
                 'invoice_clear_prepaid_ids.internal_number',
                 'voucher_ids.number',
                 'voucher_cancel_ids.number',
                 'voucher_recognize_vat_ids.number',
                 'bank_receipt_ids.name',
                 'bank_receipt_cancel_ids.name',
                 'salary_expense_ids.name',
                 'salary_expense_cancel_ids.name',
                 'expense_rev_ic_ids.number',
                 'expense_exp_ic_ids.number',
                 'account_interface_ids.number',
                 'ref',  # check for stock.picking case, as it has no move_id
                 )
    def _compute_document(self):
        for rec in self:
            document = False
            # Invoice
            if rec.invoice_ids:
                document = rec.invoice_ids[0]
            elif rec.invoice_cancel_ids:
                document = rec.invoice_cancel_ids[0]
            elif rec.invoice_clear_prepaid_ids:
                document = rec.invoice_clear_prepaid_ids[0]
            # Voucher
            elif rec.voucher_ids:
                document = rec.voucher_ids[0]
            elif rec.voucher_cancel_ids:
                document = rec.voucher_cancel_ids[0]
            elif rec.voucher_recognize_vat_ids:
                document = rec.voucher_recognize_vat_ids[0]
            # Bank Receipt
            elif rec.bank_receipt_ids:
                document = rec.bank_receipt_ids[0]
            elif rec.bank_receipt_cancel_ids:
                document = rec.bank_receipt_cancel_ids[0]
            # Salary Expense
            elif rec.salary_expense_ids:
                document = rec.salary_expense_ids[0]
            elif rec.salary_expense_cancel_ids:
                document = rec.salary_expense_cancel_ids[0]
            # Expense IC
            elif rec.expense_rev_ic_ids:
                document = rec.expense_rev_ic_ids[0]
            elif rec.expense_exp_ic_ids:
                document = rec.expense_exp_ic_ids[0]
            # Account Interface
            elif rec.account_interface_ids:
                document = rec.account_interface_ids[0]
            elif rec.ref:  # Last chance for picking, as it not have move_id
                Picking = self.env['stock.picking']
                picking = Picking.search([('name', '=', rec.ref)])
                document = picking and picking[0] or False

            # Assign reference
            if document:
                rec.document_id = '%s,%s' % (document._name, document.id)
                if document._name in ('stock.picking', 'account.bank.receipt'):
                    rec.document = document.name
                elif document._name == 'account.invoice':
                    rec.document = document.internal_number
                else:
                    rec.document = document.number
                rec.doctype = self._get_doctype(document._name, document)
                if 'date_value' in document._fields:
                    rec.date_value = document.date_value
            else:
                rec.doctype = 'adjustment'  # <-- Not related to any doc
            if not rec.date_value:
                rec.date_value = rec.date  # No Value Date, same as date

    @api.model
    def _get_doctype(self, model, document):
        if model == 'account.invoice':
            return INVOICE_DOCTYPE[document.journal_id.type]
        if model == 'account.voucher':
            return VOUCHER_DOCTYPE[document.type]
        if model == 'account.bank.receipt':
            return 'bank_receipt'
        if model == 'hr.expense.expense':
            return 'employee_expense'
        if model == 'hr.salary.expense':
            return 'salary_expense'
        if model == 'stock.picking':
            return PICKING_DOCTYPE[document.picking_type_id.code]
        if model == 'interface.account.entry':
            return 'interface_account'
Esempio n. 30
0
class OpStudent(models.Model):
    _inherit = 'op.student'

    library_card_id = fields.Many2one('op.library.card', 'Library Card')
    book_movement_lines = fields.One2many('op.book.movement', 'student_id',
                                          'Movements')