Exemple #1
0
class Inventory(models.Model):
    _name = "stock.inventory"
    _description = "Inventory"

    @api.model
    def _default_location_id(self):
        company_user = self.env.user.company_id
        warehouse = self.env['stock.warehouse'].search([('company_id', '=', company_user.id)], limit=1)
        if warehouse:
            return warehouse.lot_stock_id.id
        else:
            raise UserError(_('You must define a warehouse for the company: %s.') % (company_user.name,))

    name = fields.Char(
        'Inventory Reference',
        readonly=True, required=True,
        states={'draft': [('readonly', False)]})
    date = fields.Datetime(
        'Inventory Date',
        readonly=True, required=True,
        default=fields.Datetime.now,
        help="The date that will be used for the stock level check of the products and the validation of the stock move related to this inventory.")
    line_ids = fields.One2many(
        'stock.inventory.line', 'inventory_id', string='Inventories',
        copy=True, readonly=False,
        states={'done': [('readonly', True)]})
    move_ids = fields.One2many(
        'stock.move', 'inventory_id', string='Created Moves',
        states={'done': [('readonly', True)]})
    state = fields.Selection(string='Status', selection=[
        ('draft', 'Draft'),
        ('cancel', 'Cancelled'),
        ('confirm', 'In Progress'),
        ('done', 'Validated')],
        copy=False, index=True, readonly=True,
        default='draft')
    company_id = fields.Many2one(
        'res.company', 'Company',
        readonly=True, index=True, required=True,
        states={'draft': [('readonly', False)]},
        default=lambda self: self.env['res.company']._company_default_get('stock.inventory'))
    location_id = fields.Many2one(
        'stock.location', 'Inventoried Location',
        readonly=True, required=True,
        states={'draft': [('readonly', False)]},
        default=_default_location_id)
    product_id = fields.Many2one(
        'product.product', 'Inventoried Product',
        readonly=True,
        states={'draft': [('readonly', False)]},
        help="Specify Product to focus your inventory on a particular Product.")
    package_id = fields.Many2one(
        'stock.quant.package', 'Inventoried Pack',
        readonly=True,
        states={'draft': [('readonly', False)]},
        help="Specify Pack to focus your inventory on a particular Pack.")
    partner_id = fields.Many2one(
        'res.partner', 'Inventoried Owner',
        readonly=True,
        states={'draft': [('readonly', False)]},
        help="Specify Owner to focus your inventory on a particular Owner.")
    lot_id = fields.Many2one(
        'stock.production.lot', 'Inventoried Lot/Serial Number',
        copy=False, readonly=True,
        states={'draft': [('readonly', False)]},
        help="Specify Lot/Serial Number to focus your inventory on a particular Lot/Serial Number.")
    filter = fields.Selection(
        string='Inventory of', selection='_selection_filter',
        required=True,
        default='none',
        help="If you do an entire inventory, you can choose 'All Products' and it will prefill the inventory with the current stock.  If you only do some products  "
             "(e.g. Cycle Counting) you can choose 'Manual Selection of Products' and the system won't propose anything.  You can also let the "
             "system propose for a single product / lot /... ")
    total_qty = fields.Float('Total Quantity', compute='_compute_total_qty')
    category_id = fields.Many2one(
        'product.category', 'Inventoried Category',
        readonly=True, states={'draft': [('readonly', False)]},
        help="Specify Product Category to focus your inventory on a particular Category.")
    exhausted = fields.Boolean('Include Exhausted Products', readonly=True, states={'draft': [('readonly', False)]})

    @api.one
    @api.depends('product_id', 'line_ids.product_qty')
    def _compute_total_qty(self):
        """ For single product inventory, total quantity of the counted """
        if self.product_id:
            self.total_qty = sum(self.mapped('line_ids').mapped('product_qty'))
        else:
            self.total_qty = 0

    @api.model
    def _selection_filter(self):
        """ Get the list of filter allowed according to the options checked
        in 'Settings\Warehouse'. """
        res_filter = [
            ('none', _('All products')),
            ('category', _('One product category')),
            ('product', _('One product only')),
            ('partial', _('Select products manually'))]

        if self.user_has_groups('stock.group_tracking_owner'):
            res_filter += [('owner', _('One owner only')), ('product_owner', _('One product for a specific owner'))]
        if self.user_has_groups('stock.group_production_lot'):
            res_filter.append(('lot', _('One Lot/Serial Number')))
        if self.user_has_groups('stock.group_tracking_lot'):
            res_filter.append(('pack', _('A Pack')))
        return res_filter

    @api.onchange('filter')
    def onchange_filter(self):
        if self.filter not in ('product', 'product_owner'):
            self.product_id = False
        if self.filter != 'lot':
            self.lot_id = False
        if self.filter not in ('owner', 'product_owner'):
            self.partner_id = False
        if self.filter != 'pack':
            self.package_id = False
        if self.filter != 'category':
            self.category_id = False
        if self.filter == 'product':
            self.exhausted = True

    @api.onchange('location_id')
    def onchange_location_id(self):
        if self.location_id.company_id:
            self.company_id = self.location_id.company_id

    @api.one
    @api.constrains('filter', 'product_id', 'lot_id', 'partner_id', 'package_id')
    def _check_filter_product(self):
        if self.filter == 'none' and self.product_id and self.location_id and self.lot_id:
            return
        if self.filter not in ('product', 'product_owner') and self.product_id:
            raise UserError(_('The selected inventory options are not coherent.'))
        if self.filter != 'lot' and self.lot_id:
            raise UserError(_('The selected inventory options are not coherent.'))
        if self.filter not in ('owner', 'product_owner') and self.partner_id:
            raise UserError(_('The selected inventory options are not coherent.'))
        if self.filter != 'pack' and self.package_id:
            raise UserError(_('The selected inventory options are not coherent.'))

    @api.multi
    def action_reset_product_qty(self):
        self.mapped('line_ids').write({'product_qty': 0})
        return True
    reset_real_qty = action_reset_product_qty

    @api.multi
    def action_done(self):
        negative = next((line for line in self.mapped('line_ids') if line.product_qty < 0 and line.product_qty != line.theoretical_qty), False)
        if negative:
            raise UserError(_('You cannot set a negative product quantity in an inventory line:\n\t%s - qty: %s') % (negative.product_id.name, negative.product_qty))
        self.action_check()
        self.write({'state': 'done'})
        self.post_inventory()
        return True

    @api.multi
    def post_inventory(self):
        # The inventory is posted as a single step which means quants cannot be moved from an internal location to another using an inventory
        # as they will be moved to inventory loss, and other quants will be created to the encoded quant location. This is a normal behavior
        # as quants cannot be reuse from inventory location (users can still manually move the products before/after the inventory if they want).
        self.mapped('move_ids').filtered(lambda move: move.state != 'done').action_done()

    @api.multi
    def action_check(self):
        """ Checks the inventory and computes the stock move to do """
        # tde todo: clean after _generate_moves
        for inventory in self:
            # first remove the existing stock moves linked to this inventory
            inventory.mapped('move_ids').unlink()
            for line in inventory.line_ids:
                # compare the checked quantities on inventory lines to the theorical one
                stock_move = line._generate_moves()

    @api.multi
    def action_cancel_draft(self):
        self.mapped('move_ids').action_cancel()
        self.write({
            'line_ids': [(5,)],
            'state': 'draft'
        })

    @api.multi
    def action_start(self):
        for inventory in self:
            vals = {'state': 'confirm', 'date': fields.Datetime.now()}
            if (inventory.filter != 'partial') and not inventory.line_ids:
                vals.update({'line_ids': [(0, 0, line_values) for line_values in inventory._get_inventory_lines_values()]})
            inventory.write(vals)
        return True
    prepare_inventory = action_start

    @api.multi
    def _get_inventory_lines_values(self):
        # TDE CLEANME: is sql really necessary ? I don't think so
        locations = self.env['stock.location'].search([('id', 'child_of', [self.location_id.id])])
        domain = ' location_id in %s'
        args = (tuple(locations.ids),)

        vals = []
        Product = self.env['product.product']
        # Empty recordset of products available in stock_quants
        quant_products = self.env['product.product']
        # Empty recordset of products to filter
        products_to_filter = self.env['product.product']

        # case 0: Filter on company
        if self.company_id:
            domain += ' AND company_id = %s'
            args += (self.company_id.id,)
        
        #case 1: Filter on One owner only or One product for a specific owner
        if self.partner_id:
            domain += ' AND owner_id = %s'
            args += (self.partner_id.id,)
        #case 2: Filter on One Lot/Serial Number
        if self.lot_id:
            domain += ' AND lot_id = %s'
            args += (self.lot_id.id,)
        #case 3: Filter on One product
        if self.product_id:
            domain += ' AND product_id = %s'
            args += (self.product_id.id,)
            products_to_filter |= self.product_id
        #case 4: Filter on A Pack
        if self.package_id:
            domain += ' AND package_id = %s'
            args += (self.package_id.id,)
        #case 5: Filter on One product category + Exahausted Products
        if self.category_id:
            categ_products = Product.search([('categ_id', '=', self.category_id.id)])
            domain += ' AND product_id = ANY (%s)'
            args += (categ_products.ids,)
            products_to_filter |= categ_products

        self.env.cr.execute("""SELECT product_id, sum(qty) as product_qty, location_id, lot_id as prod_lot_id, package_id, owner_id as partner_id
            FROM stock_quant
            WHERE %s
            GROUP BY product_id, location_id, lot_id, package_id, partner_id """ % domain, args)

        for product_data in self.env.cr.dictfetchall():
            # replace the None the dictionary by False, because falsy values are tested later on
            for void_field in [item[0] for item in product_data.items() if item[1] is None]:
                product_data[void_field] = False
            product_data['theoretical_qty'] = product_data['product_qty']
            if product_data['product_id']:
                product_data['product_uom_id'] = Product.browse(product_data['product_id']).uom_id.id
                quant_products |= Product.browse(product_data['product_id'])
            vals.append(product_data)
        if self.exhausted:
            exhausted_vals = self._get_exhausted_inventory_line(products_to_filter, quant_products)
            vals.extend(exhausted_vals)
        return vals

    def _get_exhausted_inventory_line(self, products, quant_products):
        '''
        This function return inventory lines for exausted products
        :param products: products With Selected Filter.
        :param quant_products: products available in stock_quants
        '''
        vals = []
        exhausted_domain = [('type', 'not in', ('service', 'consu', 'digital'))]
        if products:
            exhausted_products = products - quant_products
            exhausted_domain += [('id', 'in', exhausted_products.ids)]
        else:
            exhausted_domain += [('id', 'not in', quant_products.ids)]
        exhausted_products = self.env['product.product'].search(exhausted_domain)
        for product in exhausted_products:
            vals.append({
                'inventory_id': self.id,
                'product_id': product.id,
                'location_id': self.location_id.id,
            })
        return vals
Exemple #2
0
class HrPayslipYear(models.Model):
    _name = 'hr.payslip.year'

    salary_rule_id = fields.Many2one('hr.salary.rule', string="Rule Name")
    total = fields.Float(string="Amount")
    hr_payslip_id = fields.Many2one('hr.payslip', string="Current Payslip Id")
class RoyaltyFeeLinestoInvoice(models.TransientModel):
    _name = 'royalty.fee.lines.to.invoice'

    royalty_fee_lines_id = fields.Many2one('royalty.fee.to.invoice')
    month = fields.Many2one('royalty.fee.month', string="Month")
    royalty_fee = fields.Float(string="Royalty Fee")
Exemple #4
0
class investasi(models.Model):
    _name = 'anggaran.investasi'
    name = fields.Char('Nomor', required=True, readonly=True)
    tanggal = fields.Date('Tanggal', required=True)
    unit_id = fields.Many2one('anggaran.unit', 'Unit Kerja')
    tahun_id = fields.Many2one('anggaran.fiscalyear', 'Tahun')
    period_id = fields.Many2one('anggaran.period', 'Perioda')
    #		keperluan = fields.Many2one('anggaran.rka_kegiatan', 'Untuk Keperluan')
    kepada_partner_id = fields.Many2one(
        'res.partner',
        'Dibayarkan Kepada',
        help="Partner (Supplier/Perorangan) penerima")
    keperluan = fields.Text("Keperluan")
    total = fields.Float("Total Biaya")

    pumkc_id = fields.Many2one('hr.employee', 'PUMKC')
    nip_pumkc = fields.Related('pumkc_id',
                               'otherid',
                               type='char',
                               relation='hr.employee',
                               string='NIP PUMKC',
                               store=True,
                               readonly=True)
    atasan_pumkc_id = fields.Many2one('hr.employee', 'Atasan Langsung PUMKC')
    nip_atasan_pumkc = fields.Related('atasan_pumkc_id',
                                      'otherid',
                                      type='char',
                                      relation='hr.employee',
                                      string='NIP Atasan PUMKC',
                                      store=True,
                                      readonly=True)

    user_id = fields.Many2one('res.users',
                              'Created',
                              required=True,
                              readonly=True)
    state = fields.Selection(INVESTASI_STATES,
                             'Status',
                             readonly=True,
                             required=True)

    _defaults = {
        'state': INVESTASI_STATES[0][0],
        'tanggal': lambda *a: time.strftime("%Y-%m-%d"),
        'user_id': lambda obj, cr, uid, context: uid,
        'name': lambda obj, cr, uid, context: '/',
    }

    def action_draft(self, cr, uid, ids, context=None):
        #set to "draft" state
        return self.write(cr,
                          uid,
                          ids, {'state': INVESTASI_STATES[0][0]},
                          context=context)

    def action_confirm(self, cr, uid, ids, context=None):
        #set to "confirmed" state
        return self.write(cr,
                          uid,
                          ids, {'state': INVESTASI_STATES[1][0]},
                          context=context)

    def action_reject(self, cr, uid, ids, context=None):
        #set to "done" state
        return self.write(cr,
                          uid,
                          ids, {'state': INVESTASI_STATES[2][0]},
                          context=context)

    def action_done(self, cr, uid, ids, context=None):
        #set to "done" state
        return self.write(cr,
                          uid,
                          ids, {'state': INVESTASI_STATES[3][0]},
                          context=context)

    def create(self, vals):
        #if context is None:
        #	context = {}
        if vals.get('name', '/') == '/':
            vals['name'] = self.env['ir.sequence'].get(
                'anggaran.investasi') or '/'
        new_id = super(investasi, self).create(vals)
        return new_id
Exemple #5
0
class IqamaRenew(models.Model):
    _name = 'iqama.renew'
    _rec_name = 'order_number'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    order_number = fields.Char(string="Order Number", readonly=True)
    employee_id = fields.Many2one('hr.employee', string="Employee")
    job_number = fields.Char(string="Job Number", )
    job_title = fields.Char("Job Title", )
    department_id = fields.Many2one('hr.department', string="Department")
    iqama_end_date = fields.Date(string="iqama_end_date")
    iqama_number = fields.Char("IQAMA NUMBER",
                               related="employee_id.identification_id")
    iqama_newstart_date = fields.Date(string="بداية الاقامة الجديدة",
                                      required=True)
    iqama_newend_date = fields.Date(string=" نهاية الاقامة الجديدة",
                                    required=True)
    reason_refuse = fields.Char(string="سبب الرفض")

    deferred_expense_models = fields.Many2one('account.asset',
                                              string="Deferred Expense Models")
    deferred_expense = fields.Many2one('account.asset',
                                       string="Deferred Expense")

    date_payed = fields.Date(string="تاريخ الدفع")
    amount = fields.Float(string="القيمة", required=True)
    journal_id = fields.Many2one('account.journal', string="اليوميه")
    account_id = fields.Many2one('account.account', string="الحساب")
    move_id = fields.Many2one('account.move', string="القيد", readonly=True)
    analytic_account_id = fields.Many2one(
        'account.analytic.account',
        'Analytic Account',
    )

    state = fields.Selection([
        ('draft', 'Draft'),
        ('hr_manager_accept', 'Hr Manager Approved'),
        ('finance_manager', 'Finance Manager Approved'),
        ('director', 'Director Approved'),
        ('accepted', 'POSTED'),
        ('cancel', 'Cancelled'),
        ("refuse", "Refuse"),
    ],
                             string='Status',
                             default='draft')

    @api.model
    def create_activity_type(self):
        modelid = (self.env['ir.model'].search([('model', '=', 'iqama.renew')
                                                ])).id
        advanced_salary = (self.env['ir.model'].search([
            ('model', '=', 'advanced.salary')
        ])).id
        advanced_salary_monthly = (self.env['ir.model'].search([
            ('model', '=', 'advanced.salary.monthly')
        ])).id
        penalty_salary = (self.env['ir.model'].search([('model', '=',
                                                        'penalty.salary')])).id
        exit_entry = (self.env['ir.model'].search([('model', '=', 'exit.entry')
                                                   ])).id
        end_employee = (self.env['ir.model'].search([('model', '=',
                                                      'end.employee')])).id

        activity = self.env['mail.activity.type']
        activity.create({
            'name': 'Iqama Renew',
            'res_model_id': modelid,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })
        activity.create({
            'name': 'Advanced Salary ',
            'res_model_id': advanced_salary,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })
        activity.create({
            'name': 'Advanced Salary monthly',
            'res_model_id': advanced_salary_monthly,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })
        activity.create({
            'name': 'Penalty Salary',
            'res_model_id': penalty_salary,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })
        activity.create({
            'name': 'Exit entry',
            'res_model_id': exit_entry,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })
        activity.create({
            'name': 'End employee',
            'res_model_id': end_employee,
            'delay_unit': 'days',
            'delay_from': 'previous_activity',
        })

    def draft_advanced(self):
        self.deferred_expense.set_to_draft()
        self.deferred_expense.unlink()

        self.move_id.button_draft()
        lines = self.env['account.move.line'].search([('move_id', '=',
                                                       self.move_id.id)])
        lines.unlink()

        modelid = (self.env['ir.model'].search([('model', '=', 'iqama.renew')
                                                ])).id
        select = "select uid from res_groups_users_rel as gs where gs.gid in (select id from res_groups as gg where name = '%s' and category_id in (select id from ir_module_category where name = '%s')   ) " % (
            'Administrator', 'Employees')
        self.env.cr.execute(select)
        results = self.env.cr.dictfetchall()
        print("wwresults", results)
        users = []
        for obj in results:
            users.append(obj['uid'])
        print("users", users)
        user_id = (self.env['res.users'].search([('id', 'in', users)]))
        activity = self.env['mail.activity']
        for user in user_id:

            activity_ins = activity.create({
                'res_id':
                self.id,
                'res_model_id':
                modelid,
                'res_model':
                'iqama.renew',
                'activity_type_id': (self.env['mail.activity.type'].search([
                    ('res_model_id', '=', modelid)
                ])).id,
                'summary':
                '',
                'note':
                '',
                'date_deadline':
                date.today(),
                'activity_category':
                'default',
                'previous_activity_type_id':
                False,
                'recommended_activity_type_id':
                False,
                'user_id':
                user.id
            })

        self.state = "draft"

    @api.model
    def create(self, vals):
        if 'order_number' not in vals:
            vals['order_number'] = self.env['ir.sequence'].next_by_code(
                'iqama.renew')
        res = super(IqamaRenew, self).create(vals)
        modelid = (self.env['ir.model'].search([('model', '=', 'iqama.renew')
                                                ])).id
        select = "select uid from res_groups_users_rel as gs where gs.gid in (select id from res_groups as gg where name = '%s' and category_id in (select id from ir_module_category where name = '%s')   ) " % (
            'Administrator', 'Employees')
        self.env.cr.execute(select)
        results = self.env.cr.dictfetchall()
        print("wwresults", results)
        users = []
        for obj in results:
            users.append(obj['uid'])
        print("users", users)
        user_id = (self.env['res.users'].search([('id', 'in', users)]))
        activity = self.env['mail.activity']
        for user in user_id:

            activity_ins = activity.create({
                'res_id':
                res.id,
                'res_model_id':
                modelid,
                'res_model':
                'iqama.renew',
                'activity_type_id': (res.env['mail.activity.type'].search([
                    ('res_model_id', '=', modelid)
                ])).id,
                'summary':
                '',
                'note':
                '',
                'date_deadline':
                date.today(),
                'activity_category':
                'default',
                'previous_activity_type_id':
                False,
                'recommended_activity_type_id':
                False,
                'user_id':
                user.id
            })
        return res

    @api.onchange('employee_id')
    def onchange_employee(self):
        if self.employee_id:
            self.job_title = self.employee_id.job_id.name
            self.job_number = self.employee_id.job_number
            self.department_id = self.employee_id.department_id.id

    def action_finance_manager(self):
        if self.env.user.has_group('account.group_account_manager'):
            activity_old = (self.env['mail.activity'].search([
                ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
            ]))
            for ac in activity_old:
                ac.action_done()

            modelid = (self.env['ir.model'].search([('model', '=',
                                                     'iqama.renew')])).id
            select = "select uid from res_groups_users_rel as gs where gs.gid in (select id from res_groups as gg where name = '%s'    ) " % (
                'Director Group')
            self.env.cr.execute(select)
            results = self.env.cr.dictfetchall()
            print("wwresults", results)
            users = []
            for obj in results:
                users.append(obj['uid'])
            print("users", users)
            user_id = (self.env['res.users'].search([('id', 'in', users)]))
            activity = self.env['mail.activity']
            for user in user_id:

                activity_ins = activity.create({
                    'res_id':
                    self.id,
                    'res_model_id':
                    modelid,
                    'res_model':
                    'iqama.renew',
                    'activity_type_id':
                    (self.env['mail.activity.type'].search([
                        ('res_model_id', '=', modelid)
                    ])).id,
                    'summary':
                    '',
                    'note':
                    '',
                    'date_deadline':
                    date.today(),
                    'activity_category':
                    'default',
                    'previous_activity_type_id':
                    False,
                    'recommended_activity_type_id':
                    False,
                    'user_id':
                    user.id
                })

            return self.write({'state': 'finance_manager'})
        else:
            raise UserError(_("لا يمكنك الموافقة صلاحية مسؤول المحاسبة"))

    def action_hr_manager_accept(self):
        if self.env.user.has_group('hr.group_hr_manager'):
            activity_old = (self.env['mail.activity'].search([
                ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
            ]))
            for ac in activity_old:
                ac.action_done()

            modelid = (self.env['ir.model'].search([('model', '=',
                                                     'iqama.renew')])).id
            select = "select uid from res_groups_users_rel as gs where gs.gid in (select id from res_groups as gg where name = '%s' and category_id in (select id from ir_module_category where name = '%s')   ) " % (
                'Advisor', 'Accounting')
            self.env.cr.execute(select)
            results = self.env.cr.dictfetchall()
            print("wwresults", results)
            users = []
            for obj in results:
                users.append(obj['uid'])
            print("users", users)
            user_id = (self.env['res.users'].search([('id', 'in', users)]))
            activity = self.env['mail.activity']
            for user in user_id:

                activity_ins = activity.create({
                    'res_id':
                    self.id,
                    'res_model_id':
                    modelid,
                    'res_model':
                    'iqama.renew',
                    'activity_type_id':
                    (self.env['mail.activity.type'].search([
                        ('res_model_id', '=', modelid)
                    ])).id,
                    'summary':
                    '',
                    'note':
                    '',
                    'date_deadline':
                    date.today(),
                    'activity_category':
                    'default',
                    'previous_activity_type_id':
                    False,
                    'recommended_activity_type_id':
                    False,
                    'user_id':
                    user.id
                })
            return self.write({'state': 'hr_manager_accept'})
        else:
            raise UserError(
                _("لا يمكنك الموافقة صلاحية مدير الموارد البشرية فقط"))
        activity_old = (self.env['mail.activity'].search([
            ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
        ]))
        for ac in activity_old:
            ac.action_done()

    def action_director(self):
        if self.env.user.has_group('payroll_edition.director_group_manager'):
            activity_old = (self.env['mail.activity'].search([
                ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
            ]))
            for ac in activity_old:
                ac.action_done()

            modelid = (self.env['ir.model'].search([('model', '=',
                                                     'iqama.renew')])).id
            select = "select uid from res_groups_users_rel as gs where gs.gid in (select id from res_groups as gg where name = '%s'   ) " % (
                'Accounting Agent')
            self.env.cr.execute(select)
            results = self.env.cr.dictfetchall()
            users = []
            for obj in results:
                users.append(obj['uid'])
            user_id = (self.env['res.users'].search([('id', 'in', users)]))
            activity = self.env['mail.activity']
            for user in user_id:
                activity_ins = activity.create({
                    'res_id':
                    self.id,
                    'res_model_id':
                    modelid,
                    'res_model':
                    'iqama.renew',
                    'activity_type_id':
                    (self.env['mail.activity.type'].search([
                        ('res_model_id', '=', modelid)
                    ])).id,
                    'summary':
                    '',
                    'note':
                    '',
                    'date_deadline':
                    date.today(),
                    'activity_category':
                    'default',
                    'previous_activity_type_id':
                    False,
                    'recommended_activity_type_id':
                    False,
                    'user_id':
                    user.id
                })

            return self.write({'state': 'director'})
        else:
            raise UserError(_("لا يمكنك الموافقة صلاحية الادارة فقط"))

    def return_movelines(self):
        all_move_vals = []
        for rec in self:

            move_vals = {
                'date':
                rec.date_payed,
                'ref':
                rec.order_number,
                'journal_id':
                rec.journal_id.id,
                'line_ids': [
                    (0, 0, {
                        'name': rec.order_number,
                        'debit': rec.amount,
                        'credit': 0.0,
                        'account_id': rec.account_id.id,
                        'analytic_account_id': rec.analytic_account_id.id,
                        'partner_id': rec.employee_id.address_home_id.id,
                    }),
                    (0, 0, {
                        'name': rec.order_number,
                        'debit': 0.0,
                        'credit': rec.amount,
                        'account_id':
                        rec.journal_id.default_credit_account_id.id,
                        'analytic_account_id': rec.analytic_account_id.id,
                        'partner_id': rec.employee_id.address_home_id.id,
                    }),
                ],
            }
            all_move_vals.append(move_vals)
            return all_move_vals

    def action_accepted(self):
        if self.env.user.has_group(
                'payroll_edition.accounting_agent_group_manager'
        ) or self.env.user.has_group('account.group_account_manager'):
            if not self.account_id or not self.journal_id or not self.date_payed or not self.deferred_expense_models:
                raise UserError(
                    _("يجب تعبئة الحقول المستخدمة في عملية انشاء القيود"))

            account_asset = self.env['account.asset']
            res_asset = account_asset.create({
                'asset_type':
                'expense',
                'state':
                'draft',
                'name':
                self.deferred_expense_models.name,
                'original_value':
                self.amount,
                'acquisition_date':
                self.date_payed,
                'method_number':
                self.deferred_expense_models.method_number,
                'method_period':
                self.deferred_expense_models.method_period,
                'account_depreciation_id':
                self.deferred_expense_models.account_depreciation_id.id,
                'account_depreciation_expense_id':
                self.deferred_expense_models.account_depreciation_expense_id.
                id,
                'journal_id':
                self.deferred_expense_models.journal_id.id,
                'account_analytic_id':
                self.deferred_expense_models.account_analytic_id.id,
                'analytic_tag_ids':
                self.deferred_expense_models.analytic_tag_ids.ids
            })
            print("res_asset", res_asset)
            self.deferred_expense = res_asset.id
            self.deferred_expense.compute_depreciation_board()
            self.deferred_expense.validate()

            self.employee_id.iqama_start_date = self.iqama_newstart_date
            self.employee_id.iqama_end_date = self.iqama_newend_date
            AccountMove = self.env['account.move'].with_context(
                default_type='entry')
            if not self.move_id:
                moves = AccountMove.create(self.return_movelines())
                moves.post()
                self.move_id = moves.id
            else:
                self.move_id.button_draft()
                self.move_id.date = self.date_payed
                move_line_vals = []
                line1 = (0, 0, {
                    'name': self.order_number,
                    'debit': self.amount,
                    'credit': 0,
                    'account_id': self.account_id.id,
                    'partner_id': self.employee_id.address_home_id.id,
                    'analytic_account_id': self.analytic_account_id.id
                })
                line2 = (0, 0, {
                    'name':
                    self.order_number,
                    'debit':
                    0,
                    'credit':
                    self.amount,
                    'account_id':
                    self.journal_id.default_credit_account_id.id,
                    'partner_id':
                    self.employee_id.address_home_id.id,
                    'analytic_account_id':
                    self.analytic_account_id.id
                })
                move_line_vals.append(line1)
                move_line_vals.append(line2)
                self.move_id.line_ids = move_line_vals
                self.move_id.post()
            activity_old = (self.env['mail.activity'].search([
                ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
            ]))
            for ac in activity_old:
                ac.action_done()

            return self.write({'state': 'accepted'})
        else:
            raise UserError(_("لا يمكنك الموافقة صلاحية الادارة فقط"))

    def refuse_go(self):
        if self.state == "draft":
            if self.env.user.has_group('hr.group_hr_manager'):
                self.state = "refuse"
            else:
                raise UserError(
                    _("لا يمكنك الموافقة صلاحية مدير الموارد البشرية فقط"))

        elif self.state == "hr_manager_accept":
            if self.env.user.has_group('account.group_account_manager'):
                self.state = "refuse"
            else:
                raise UserError(_("لا يمكنك الموافقة صلاحية مسؤول المحاسبة"))

        elif self.state == "finance_manager":
            if self.env.user.has_group(
                    'payroll_edition.director_group_manager'):
                self.state = "refuse"
            else:
                raise UserError(_("لا يمكنك الموافقة صلاحية الادارة فقط"))
        if not self.reason_refuse:
            raise UserError(_("يجب تعبئة حقل سبب الرفض"))

        activity_old = (self.env['mail.activity'].search([
            ('res_model', '=', 'exit.entry'), ('res_id', '=', self.id)
        ]))
        for ac in activity_old:
            ac.action_done()

    def action_cancel(self):
        activity_old = (self.env['mail.activity'].search([
            ('res_model', '=', 'iqama.renew'), ('res_id', '=', self.id)
        ]))
        for ac in activity_old:
            ac.action_done()

        return self.write({'state': 'cancel'})
Exemple #6
0
class MrpWorkcenter(models.Model):
    _name = 'mrp.workcenter'
    _description = 'Work Center'
    _order = "sequence, id"
    _inherit = ['resource.mixin']

    # resource
    name = fields.Char(related='resource_id.name', store=True)
    time_efficiency = fields.Float('Time Efficiency',
                                   related='resource_id.time_efficiency',
                                   default=100,
                                   store=True)
    active = fields.Boolean('Active',
                            related='resource_id.active',
                            default=True,
                            store=True)

    code = fields.Char('Code', copy=False)
    note = fields.Text('Description', help="Description of the Work Center.")
    capacity = fields.Float(
        'Capacity',
        default=1.0,
        oldname='capacity_per_cycle',
        help="Number of pieces that can be produced in parallel.")
    sequence = fields.Integer(
        'Sequence',
        default=1,
        required=True,
        help="Gives the sequence order when displaying a list of work centers."
    )
    color = fields.Integer('Color')
    time_start = fields.Float('Time before prod.',
                              help="Time in minutes for the setup.")
    time_stop = fields.Float('Time after prod.',
                             help="Time in minutes for the cleaning.")
    routing_line_ids = fields.One2many('mrp.routing.workcenter',
                                       'workcenter_id', "Routing Lines")
    order_ids = fields.One2many('mrp.workorder', 'workcenter_id', "Orders")
    workorder_count = fields.Integer('# Work Orders',
                                     compute='_compute_workorder_count')
    workorder_ready_count = fields.Integer('# Read Work Orders',
                                           compute='_compute_workorder_count')
    workorder_progress_count = fields.Integer(
        'Total Running Orders', compute='_compute_workorder_count')
    workorder_pending_count = fields.Integer(
        'Total Pending Orders', compute='_compute_workorder_count')
    workorder_late_count = fields.Integer('Total Late Orders',
                                          compute='_compute_workorder_count')

    time_ids = fields.One2many('mrp.workcenter.productivity', 'workcenter_id',
                               'Time Logs')
    working_state = fields.Selection([('normal', 'Normal'),
                                      ('blocked', 'Blocked'),
                                      ('done', 'In Progress')],
                                     'Workcenter Status',
                                     compute="_compute_working_state",
                                     store=True)
    blocked_time = fields.Float('Blocked Time',
                                compute='_compute_blocked_time',
                                help='Blocked hour(s) over the last month',
                                digits=(16, 2))
    productive_time = fields.Float(
        'Productive Time',
        compute='_compute_productive_time',
        help='Productive hour(s) over the last month',
        digits=(16, 2))
    oee = fields.Float(
        compute='_compute_oee',
        help='Overall Equipment Effectiveness, based on the last month')
    oee_target = fields.Float(string='OEE Target',
                              help="OEE Target in percentage",
                              default=90)
    performance = fields.Integer('Performance',
                                 compute='_compute_performance',
                                 help='Performance over the last month')
    workcenter_load = fields.Float('Work Center Load',
                                   compute='_compute_workorder_count')

    @api.depends('order_ids.duration_expected', 'order_ids.workcenter_id',
                 'order_ids.state', 'order_ids.date_planned_start')
    def _compute_workorder_count(self):
        MrpWorkorder = self.env['mrp.workorder']
        result = {wid: {} for wid in self.ids}
        result_duration_expected = {wid: 0 for wid in self.ids}
        #Count Late Workorder
        data = MrpWorkorder.read_group(
            [('workcenter_id', 'in', self.ids),
             ('state', 'in', ('pending', 'ready')),
             ('date_planned_start', '<',
              datetime.datetime.now().strftime('%Y-%m-%d'))],
            ['workcenter_id'], ['workcenter_id'])
        count_data = dict(
            (item['workcenter_id'][0], item['workcenter_id_count'])
            for item in data)
        #Count All, Pending, Ready, Progress Workorder
        res = MrpWorkorder.read_group(
            [('workcenter_id', 'in', self.ids)],
            ['workcenter_id', 'state', 'duration_expected'],
            ['workcenter_id', 'state'],
            lazy=False)
        for res_group in res:
            result[res_group['workcenter_id'][0]][
                res_group['state']] = res_group['__count']
            if res_group['state'] in ('pending', 'ready', 'progress'):
                result_duration_expected[res_group['workcenter_id']
                                         [0]] += res_group['duration_expected']
        for workcenter in self:
            workcenter.workorder_count = sum(
                count for state, count in result[workcenter.id].items()
                if state not in ('done', 'cancel'))
            workcenter.workorder_pending_count = result[workcenter.id].get(
                'pending', 0)
            workcenter.workcenter_load = result_duration_expected[
                workcenter.id]
            workcenter.workorder_ready_count = result[workcenter.id].get(
                'ready', 0)
            workcenter.workorder_progress_count = result[workcenter.id].get(
                'progress', 0)
            workcenter.workorder_late_count = count_data.get(workcenter.id, 0)

    @api.multi
    @api.depends('time_ids', 'time_ids.date_end', 'time_ids.loss_type')
    def _compute_working_state(self):
        for workcenter in self:
            # We search for a productivity line associated to this workcenter having no `date_end`.
            # If we do not find one, the workcenter is not currently being used. If we find one, according
            # to its `type_loss`, the workcenter is either being used or blocked.
            time_log = self.env['mrp.workcenter.productivity'].search(
                [('workcenter_id', '=', workcenter.id),
                 ('date_end', '=', False)],
                limit=1)
            if not time_log:
                # the workcenter is not being used
                workcenter.working_state = 'normal'
            elif time_log.loss_type in ('productive', 'performance'):
                # the productivity line has a `loss_type` that means the workcenter is being used
                workcenter.working_state = 'done'
            else:
                # the workcenter is blocked
                workcenter.working_state = 'blocked'

    @api.multi
    def _compute_blocked_time(self):
        # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently ??
        data = self.env['mrp.workcenter.productivity'].read_group([
            ('date_start', '>=',
             fields.Datetime.to_string(datetime.datetime.now() -
                                       relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids), ('date_end', '!=', False),
            ('loss_type', '!=', 'productive')
        ], ['duration', 'workcenter_id'], ['workcenter_id'],
                                                                  lazy=False)
        count_data = dict(
            (item['workcenter_id'][0], item['duration']) for item in data)
        for workcenter in self:
            workcenter.blocked_time = count_data.get(workcenter.id, 0.0) / 60.0

    @api.multi
    def _compute_productive_time(self):
        # TDE FIXME: productivity loss type should be only losses, probably count other time logs differently
        data = self.env['mrp.workcenter.productivity'].read_group([
            ('date_start', '>=',
             fields.Datetime.to_string(datetime.datetime.now() -
                                       relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids), ('date_end', '!=', False),
            ('loss_type', '=', 'productive')
        ], ['duration', 'workcenter_id'], ['workcenter_id'],
                                                                  lazy=False)
        count_data = dict(
            (item['workcenter_id'][0], item['duration']) for item in data)
        for workcenter in self:
            workcenter.productive_time = count_data.get(workcenter.id,
                                                        0.0) / 60.0

    @api.depends('blocked_time', 'productive_time')
    def _compute_oee(self):
        for order in self:
            if order.productive_time:
                order.oee = round(
                    order.productive_time * 100.0 /
                    (order.productive_time + order.blocked_time), 2)
            else:
                order.oee = 0.0

    @api.multi
    def _compute_performance(self):
        wo_data = self.env['mrp.workorder'].read_group([
            ('date_start', '>=',
             fields.Datetime.to_string(datetime.datetime.now() -
                                       relativedelta.relativedelta(months=1))),
            ('workcenter_id', 'in', self.ids), ('state', '=', 'done')
        ], ['duration_expected', 'workcenter_id', 'duration'],
                                                       ['workcenter_id'],
                                                       lazy=False)
        duration_expected = dict(
            (data['workcenter_id'][0], data['duration_expected'])
            for data in wo_data)
        duration = dict(
            (data['workcenter_id'][0], data['duration']) for data in wo_data)
        for workcenter in self:
            if duration.get(workcenter.id):
                workcenter.performance = 100 * duration_expected.get(
                    workcenter.id, 0.0) / duration[workcenter.id]
            else:
                workcenter.performance = 0.0

    @api.multi
    @api.constrains('capacity')
    def _check_capacity(self):
        if any(workcenter.capacity <= 0.0 for workcenter in self):
            raise exceptions.UserError(
                _('The capacity must be strictly positive.'))

    @api.multi
    def unblock(self):
        self.ensure_one()
        if self.working_state != 'blocked':
            raise exceptions.UserError(_("It has been unblocked already. "))
        times = self.env['mrp.workcenter.productivity'].search([
            ('workcenter_id', '=', self.id), ('date_end', '=', False)
        ])
        times.write({'date_end': fields.Datetime.now()})
        return {'type': 'ir.actions.client', 'tag': 'reload'}
Exemple #7
0
class Deduction(models.Model):
    _name = 'deduction.deduction'
    _inherit = 'mail.thread'

    name = fields.Char(string='Reference', required=True)
    deduction_no = fields.Char(string='Sequence', readonly=True)
    date = fields.Date(string="Date", default=date.today())
    employee = fields.Many2one('hr.employee',
                               string="Employee",
                               required=False)
    deduction_type = fields.Many2one('deduction.type',
                                     string='Deduction Type',
                                     required=True)
    fix_formula = fields.Selection([('formula', 'Formula'), ("fix", "Fixed")],
                                   string='Calculation Type',
                                   required=True,
                                   default='fix')
    amount = fields.Float(string="Amount")
    description = fields.Text(string='Description', required=True)
    state = fields.Selection([('draft', 'Draft'), ("confirm", "Confirm"),
                              ('hr_manager', 'Hr'), ('done', 'Done')],
                             default='draft',
                             string='State',
                             track_visibility='onchange')
    voucher_ref = fields.Many2one('account.voucher',
                                  string='Voucher reference',
                                  readonly=True)
    is_paid = fields.Boolean()
    formual = fields.Text(placeholder="result=(wage/30)*1")

    @api.multi
    def unlink(self):
        for rec in self:
            if rec.state != 'draft':
                raise UserError(
                    _('You cannot delete Form which is not is draft.'))
        return super(Deduction, self).unlink()

    @api.multi
    def action_confirm(self):
        for rec in self:
            if rec.amount <= 0:
                if rec.fix_formula != 'fix':
                    raise ValidationError(
                        "Please click on calc amount button, and amount must be greater than zero"
                    )
                raise ValidationError(_("Amount Must Be Greater Than Zero"))
            if rec.state == 'draft':
                rec.state = 'confirm'
            #     if rec.deduction_type.pay_included == 'voucher':
            #         self.generate_voucher()
            # else:
            #     raise UserError("In order to confirm this deduction state must be in draft")

    @api.one
    def generate_voucher(self):
        voucher_obj = self.env['account.voucher']
        payable_account_id = self._default_payable_account_id()
        expense_account_id = self._default_expense_account_id()
        journal_id = self._default_journal_id()
        if not payable_account_id:
            raise ValidationError(
                "Please check configuration for default voucher payable account"
            )
        if not expense_account_id:
            raise ValidationError(
                "Please check configuration for default voucher expense account"
            )
        if not journal_id:
            raise ValidationError(
                "Please check configuration for default voucher journal")

        if self.deduction_type.pay_included == 'voucher':
            employee_default_account_id = self.employee.address_home_id and self.employee.address_home_id.property_account_payable_id
            voucher_id = voucher_obj.create({
                'journal_id':
                journal_id.id,
                'voucher_type':
                'purchase',
                'pay_now':
                'pay_later',
                'state':
                'draft',
                'account_id':
                employee_default_account_id.id or payable_account_id.id,
                'line_ids': [(0, 0, {
                    'name': self.description or '/',
                    'quantity': 1,
                    'price_unit': self.amount,
                    'account_id': expense_account_id.id
                })]
            })

            voucher_id.proforma_voucher()
            self.write({'voucher_ref': voucher_id.id})

    @api.model
    def _default_payable_account_id(self):
        account_id = self.env['ir.config_parameter'].sudo().get_param(
            'penalties_custom_12.default_voucher_payable_account_id')
        return self.env['account.account'].browse(int(account_id))

    @api.model
    def _default_expense_account_id(self):
        account_id = self.env['ir.config_parameter'].sudo().get_param(
            'penalties_custom_12.default_voucher_expense_account_id')
        return self.env['account.account'].browse(int(account_id))

    @api.model
    def _default_journal_id(self):
        journal_id = self.env['ir.config_parameter'].sudo().get_param(
            'penalties_custom_12.default_journal_id')
        return self.env['account.journal'].browse(int(journal_id))

    @api.multi
    def action_hr_approval(self):
        for rec in self:
            if rec.state == 'confirm':
                rec.state = 'hr_manager'
            else:
                raise (_(
                    "In order to approve this deduction state must be in confirm"
                ))

    def set_amount(self):
        for rec in self:
            amount = self.calc_amount(employee_id=rec.employee,
                                      contract=rec.employee.contract_id,
                                      rec=self).get('result', False)
            rec.amount = amount

    @api.onchange('fix_formula')
    def set_formula(self):
        if not self.formual:
            self.formual = self.deduction_type.formual

    @api.model
    def _default_calc_formula(self):
        calc_formula = self.env['ir.config_parameter'].sudo().get_param(
            'penalties_custom_12.calc_formula')
        return self.formual

    def calc_amount(self, employee_id, contract, rec):
        employee = self.env['hr.employee'].browse(employee_id)
        formula_data = self._default_calc_formula()
        if not formula_data:
            raise ValidationError(
                "Please Check payroll Configuration. Set formula")
        localdict = {
            "employee_id": employee,
            "wage": contract.wage,
            "deduction": self,
            "contract": contract,
            'result': 0
        }
        safe_eval(formula_data, localdict, mode='exec', nocopy=True)
        return localdict

    @api.multi
    def action_ceo_approve(self):
        for rec in self:
            if rec.state == 'hr_manager':
                rec.state = 'done'
            else:
                raise (_(
                    "In order to ceo approve this deduction state must be in hr approve"
                ))
Exemple #8
0
class HrPayslip(models.Model):
    _inherit = 'hr.payslip'

    age = fields.Float('Age', compute='_compute_age_service')
    service_period = fields.Float('Service Period', compute='_compute_age_service')
    work = fields.Float('Working Period', compute='_compute_age_service')
    zw_idara = fields.Many2one(related='employee_id.zw_idara', string='Location', store=True)
    is_refund = fields.Boolean(string="Refund")
    employee_code = fields.Char('Employee ID', related='employee_id.employee_id', store=True)

    @api.multi
    def refund_sheet(self):
        for payslip in self:
            if payslip.is_refund:
                raise UserError(_('You Cannot Refund Payslip More one time.'))
            copied_payslip = payslip.copy(
                {'credit_note': True, 'is_refund': True, 'name': _('Refund: ') + payslip.name})
            payslip.update({'is_refund': True})
            copied_payslip.input_line_ids = payslip.input_line_ids
            copied_payslip.compute_sheet()
            copied_payslip.action_payslip_done()
        formview_ref = self.env.ref('hr_payroll.view_hr_payslip_form', False)
        treeview_ref = self.env.ref('hr_payroll.view_hr_payslip_tree', False)
        return {
            'name': ("Refund Payslip"),
            'view_mode': 'tree, form',
            'view_id': False,
            'view_type': 'form',
            'res_model': 'hr.payslip',
            'type': 'ir.actions.act_window',
            'target': 'current',
            'domain': "[('id', 'in', %s)]" % copied_payslip.ids,
            'views': [(treeview_ref and treeview_ref.id or False, 'tree'),
                      (formview_ref and formview_ref.id or False, 'form')],
            'context': {}
        }

    @api.model
    def create(self, values):
        res = super(HrPayslip, self).create(values)
        payrolls = self.search([('employee_id', '=', res.employee_id.id)]).filtered(lambda pay: not pay.is_refund)
        for payroll in payrolls:
            if payroll.id != res.id and not res.is_refund:
                if (payroll.date_to >= res.date_from >= payroll.date_from) or (
                        payroll.date_to >= res.date_to >= payroll.date_from):
                    raise UserError(_('You Cannot Create Two Payslips for one Employee In Same Period.'))
        return res

    @api.one
    def _compute_age_service(self):
        if self.employee_id.birthday:
            today = fields.date.today()
            born = datetime.strptime(str(self.employee_id.birthday), '%Y-%m-%d')
            self.age = today.year - born.year - ((today.month, today.day) < (born.month, born.day))
        if self.employee_id.joining_date:
            today = fields.date.today()
            join_date = datetime.strptime(str(self.employee_id.joining_date), '%Y-%m-%d')
            diff = today - join_date.date()
            self.service_period = round((diff.days / 365) * 12, 2)
        if self.date_from and self.date_to:
            from_date = fields.Datetime.from_string(self.date_from)
            to_date = fields.Datetime.from_string(self.date_to)
            self.work = (to_date - from_date).days + 1

    @api.onchange('employee_id', 'date_from', 'date_to')
    def onchange_employee(self):
        self.contract_id = False
        res = super(HrPayslip, self).onchange_employee()
        if self.employee_id.birthday:
            today = fields.date.today()
            born = datetime.strptime(str(self.employee_id.birthday), '%Y-%m-%d')
            self.age = today.year - born.year - ((today.month, today.day) < (born.month, born.day))
        if self.employee_id.joining_date:
            today = fields.date.today()
            join_date = datetime.strptime(str(self.employee_id.joining_date), '%Y-%m-%d')
            diff = today - join_date.date()
            self.service_period = round((diff.days / 365) * 12, 2)
        if self.date_from:
            date_from = fields.Datetime.from_string(self.date_from)
            self.date_to = str(date_from + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10]
        return res

    @api.model
    def get_worked_day_lines(self, contract_ids, date_from, date_to):
        res = super(HrPayslip, self).get_worked_day_lines(contract_ids, date_from, date_to)
        for contract in contract_ids:
            overtime = {
                'name': 'Number of Hours Overtime',
                'sequence': 11,
                'code': 'Overtime',
                'number_of_days': 0.0,
                'number_of_hours': 0.0,
                'contract_id': contract.id,
            }
            absence = {
                'name': 'Number of Days Absence',
                'sequence': 12,
                'code': 'Absence',
                'number_of_days': 0.0,
                'number_of_hours': 0.0,
                'contract_id': contract.id,
            }
            unpaid = {
                'name': 'Number of Days UnPaid',
                'sequence': 13,
                'code': 'UnPaid',
                'number_of_days': 0.0,
                'number_of_hours': 0.0,
                'contract_id': contract.id,
            }
            late = {
                'name': 'Number of Hours Late',
                'sequence': 14,
                'code': 'Late',
                'number_of_days': 0.0,
                'number_of_hours': 0.0,
                'contract_id': contract.id,
            }
            res.append(overtime)
            res.append(absence)
            res.append(unpaid)
            res.append(late)
        return res
Exemple #9
0
class SaleOrderLine(models.Model):

    _inherit = 'sale.order.line'

    # We compute as sudo consultant does not have access to invoices which is required when
    # he logs time from a task
    qty_invoiced = fields.Float(compute_sudo=True)

    vcls_type = fields.Selection(
        related='product_id.vcls_type',
        string="Vcls type",
    )

    # Override the default ordered quantity to be 0 when we order rates items
    product_uom_qty = fields.Float(
        default=0,
    )

    section_line_id = fields.Many2one(
        'sale.order.line',
        string='Line section',
        compute='_get_section_line_id',
        store=False
    )

    @api.multi
    def _get_section_line_id(self):
        for line in self:
            order_line_ids = line.order_id.order_line
            current_section_line_id = False
            for order_line_id in order_line_ids:
                if order_line_id.display_type == 'line_section':
                    current_section_line_id = order_line_id
                elif line == order_line_id:
                    line.section_line_id = current_section_line_id
                    break

    def _timesheet_create_project(self):
        project = super(SaleOrderLine, self)._timesheet_create_project()
        project.update({'project_type': 'client'})
        return project

    # We override the line creation in order to link them with existing project
    @api.model_create_multi
    def create(self, vals_list):
        if vals_list[0].get('order_id',False):
            order = self.env['sale.order'].browse(vals_list[0]['order_id'])
            self = self.with_context(force_company=order.company_id.id)
        
        lines = super(SaleOrderLine, self).create(vals_list)
        
        for line in lines:
            if (line.product_id.service_tracking in ['project_only', 'task_new_project']) and not line.product_id.project_template_id:
                line.project_id = line.order_id.project_id
        
        return lines

    @api.multi
    def unlink(self):
        for order_line in self:
            related_timesheet = self.env['account.analytic.line'].sudo().search([
                ('so_line', '=', order_line.id),
            ], limit=1)
            if related_timesheet:
                raise ValidationError(
                    _('You can not delete the "{}" order line has linked timesheets.'.format(order_line.name))
                )
            related_mapping = self.env['project.sale.line.employee.map'].sudo().search([
                ('sale_line_id', '=', order_line.id),
            ])
            # delete mapping linked forecast
            rate_employee = related_mapping.mapped('employee_id')

            # forecast deletion
            # in case this line is a service: delete forecast related to service line
            forecast_domain = [
                ('order_line_id', '=', order_line.id),
            ]
            # Now in case this line is a rate , we search for all forecasts
            # having the the same rate employee (employee_id) using the mapping table
            # within the same project
            if rate_employee and order_line.order_id.project_id:
                forecast_domain = expression.OR([
                    forecast_domain, [
                        '&',
                        ('employee_id', 'in', rate_employee.ids),
                        ('project_id', '=', order_line.order_id.project_id.id),
                    ]
                ])

            related_forecasts = self.env['project.forecast'].sudo().search(forecast_domain)
            
            if related_forecasts:
                related_forecasts.sudo().unlink()

            # delete mapping
            if related_mapping:
                related_mapping.sudo().unlink()

            if order_line.vcls_type != 'rate':
                related_task = self.env['project.task'].sudo().search([
                    '|',
                    ('sale_line_id', '=', order_line.id),
                    ('parent_id.sale_line_id', '=', order_line.id),
                ])
                if related_task:
                    related_task.write({'sale_line_id': False})
                    related_task.sudo().unlink()
        return super(SaleOrderLine, self).unlink()
Exemple #10
0
class CrmTeam(models.Model):
    _inherit = 'crm.team'

    use_quotations = fields.Boolean(
        string='Quotations',
        help=
        "Check this box if you send quotations to your customers rather than confirming orders straight away."
    )
    invoiced = fields.Float(
        compute='_compute_invoiced',
        string='Invoiced This Month',
        readonly=True,
        help=
        "Invoice revenue for the current month. This is the amount the sales "
        "channel has invoiced this month. It is used to compute the progression ratio "
        "of the current and target revenue on the kanban view.")
    invoiced_target = fields.Float(
        string='Invoicing Target',
        help=
        "Revenue target for the current month (untaxed total of confirmed invoices)."
    )
    quotations_count = fields.Integer(compute='_compute_quotations_to_invoice',
                                      string='Number of quotations to invoice',
                                      readonly=True)
    quotations_amount = fields.Float(compute='_compute_quotations_to_invoice',
                                     string='Amount of quotations to invoice',
                                     readonly=True)
    sales_to_invoice_count = fields.Integer(
        compute='_compute_sales_to_invoice',
        string='Number of sales to invoice',
        readonly=True)
    sale_order_count = fields.Integer(compute='_compute_sale_order_count',
                                      string='# Sale Orders')

    def _compute_quotations_to_invoice(self):
        query = self.env['sale.order']._where_calc([
            ('team_id', 'in', self.ids),
            ('state', 'in', ['draft', 'sent']),
        ])
        self.env['sale.order']._apply_ir_rules(query, 'read')
        _, where_clause, where_clause_args = query.get_sql()
        select_query = """
            SELECT team_id, count(*), sum(amount_total /
                CASE COALESCE(currency_rate, 0)
                WHEN 0 THEN 1.0
                ELSE currency_rate
                END
            ) as amount_total
            FROM sale_order
            WHERE %s
            GROUP BY team_id
        """ % where_clause
        self.env.cr.execute(select_query, where_clause_args)
        quotation_data = self.env.cr.dictfetchall()
        teams = self.browse()
        for datum in quotation_data:
            team = self.browse(datum['team_id'])
            team.quotations_amount = datum['amount_total']
            team.quotations_count = datum['count']
            teams |= team
        remaining = (self - teams)
        remaining.quotations_amount = 0
        remaining.quotations_count = 0

    def _compute_sales_to_invoice(self):
        sale_order_data = self.env['sale.order']._read_group([
            ('team_id', 'in', self.ids),
            ('invoice_status', '=', 'to invoice'),
        ], ['team_id'], ['team_id'])
        data_map = {
            datum['team_id'][0]: datum['team_id_count']
            for datum in sale_order_data
        }
        for team in self:
            team.sales_to_invoice_count = data_map.get(team.id, 0.0)

    def _compute_invoiced(self):
        if not self:
            return

        query = '''
            SELECT
                move.team_id AS team_id,
                SUM(move.amount_untaxed_signed) AS amount_untaxed_signed
            FROM account_move move
            WHERE move.move_type IN ('out_invoice', 'out_refund', 'out_receipt')
            AND move.payment_state IN ('in_payment', 'paid', 'reversed')
            AND move.state = 'posted'
            AND move.team_id IN %s
            AND move.date BETWEEN %s AND %s
            GROUP BY move.team_id
        '''
        today = fields.Date.today()
        params = [
            tuple(self.ids),
            fields.Date.to_string(today.replace(day=1)),
            fields.Date.to_string(today)
        ]
        self._cr.execute(query, params)

        data_map = dict((v[0], v[1]) for v in self._cr.fetchall())
        for team in self:
            team.invoiced = data_map.get(team.id, 0.0)

    def _compute_sale_order_count(self):
        data_map = {}
        if self.ids:
            sale_order_data = self.env['sale.order']._read_group([
                ('team_id', 'in', self.ids),
                ('state', '!=', 'cancel'),
            ], ['team_id'], ['team_id'])
            data_map = {
                datum['team_id'][0]: datum['team_id_count']
                for datum in sale_order_data
            }
        for team in self:
            team.sale_order_count = data_map.get(team.id, 0)

    def _graph_get_model(self):
        if self._context.get('in_sales_app'):
            return 'sale.report'
        return super(CrmTeam, self)._graph_get_model()

    def _graph_date_column(self):
        if self._context.get('in_sales_app'):
            return 'date'
        return super(CrmTeam, self)._graph_date_column()

    def _graph_y_query(self):
        if self._context.get('in_sales_app'):
            return 'SUM(price_subtotal)'
        return super(CrmTeam, self)._graph_y_query()

    def _extra_sql_conditions(self):
        if self._context.get('in_sales_app'):
            return "AND state in ('sale', 'done', 'pos_done')"
        return super(CrmTeam, self)._extra_sql_conditions()

    def _graph_title_and_key(self):
        if self._context.get('in_sales_app'):
            return ['', _('Sales: Untaxed Total')]  # no more title
        return super(CrmTeam, self)._graph_title_and_key()

    def _compute_dashboard_button_name(self):
        super(CrmTeam, self)._compute_dashboard_button_name()
        if self._context.get('in_sales_app'):
            self.update({'dashboard_button_name': _("Sales Analysis")})

    def action_primary_channel_button(self):
        if self._context.get('in_sales_app'):
            return self.env["ir.actions.actions"]._for_xml_id(
                "sale.action_order_report_so_salesteam")
        return super(CrmTeam, self).action_primary_channel_button()

    def update_invoiced_target(self, value):
        return self.write({'invoiced_target': round(float(value or 0))})

    @api.ondelete(at_uninstall=False)
    def _unlink_except_used_for_sales(self):
        """ If more than 5 active SOs, we consider this team to be actively used.
        5 is some random guess based on "user testing", aka more than testing
        CRM feature and less than use it in real life use cases. """
        SO_COUNT_TRIGGER = 5
        for team in self:
            if team.sale_order_count >= SO_COUNT_TRIGGER:
                raise UserError(
                    _('Team %(team_name)s has %(sale_order_count)s active sale orders. Consider canceling them or archiving the team instead.',
                      team_name=team.name,
                      sale_order_count=team.sale_order_count))
class HRStaffSalaryDifference(models.Model):		
	_name = "hr.staff.salary.difference"
	_inherit = ['mail.thread']
	_description = "HR Staff Salary Difference"
	
	@api.one
	@api.depends('line_ids','line_ids.amount')
	def _get_total_amount(self):
		total = 0
		for line_id in self.line_ids:
			total += line_id.amount
		self.total = total	
	
	name = fields.Char("Name",required=True)
	date = fields.Date('Date',default=lambda self: datetime.today().strftime('%Y-%m-%d'),track_visibility='onchange')
	segment_id = fields.Many2one('hr.segmentation','Segment', default=1,track_visibility='onchange')	
	salary_payable_account = fields.Many2one('account.account','Salary Payable Account',required=True,readonly=True, default=141, track_visibility='onchange')
	expense_account = fields.Many2one('account.account','Expense Account',required=True,readonly=True,default=111,track_visibility='onchange')
	journal_id = fields.Many2one('account.journal','Journal', default=41,track_visibility='onchange')
	move_id = fields.Many2one('account.move','Accounting Entry',readonly=True)
	state = fields.Selection([('draft','Draft'),('validate','Validate'),('paid','Paid')],'Status',default='draft', track_visibility='onchange')
	total = fields.Float(compute='_get_total_amount',string='Total', required=False,store=True)
	line_ids = fields.One2many('hr.staff.salary.difference.line', 'difference_id', 'Lines')
	date_from = fields.Date('Date From', required=True,default=lambda *a: str(datetime.now() + relativedelta.relativedelta(day=1))[:10])
	date_to = fields.Date('Date To', required=True,default=lambda *a: str(datetime.now() + relativedelta.relativedelta(day=31))[:10])
	note = fields.Text('Note')
	
	
	@api.one	
	def unlink(self):
		if self.state != 'draft':
			raise UserError(('You can not delete Record which are not in Draft State. Please Shift First in  Draft state then delete it.'))
		ret = super(hr_staff_salary_difference, self).unlink()
		return ret
		
	@api.one	
	def salary_validate(self):
		self.state = 'validate'
	
	@api.one	
	def salary_paid(self):
		move_obj = self.env['account.move']
		move_lines = []
		timenow = time.strftime('%Y-%m-%d')
		
		model_rec = self.env['ir.model'].search([('model','=','hr.staff.salary.difference')])
		auto_entries = self.env['auto.dimensions.entry'].search([('model_id','=',model_rec.id),('active','=',True)],order='sequence')
		
		name = self.name
		move = {
			'narration': self.name,
			'date': self.date or timenow,
			'journal_id': self.journal_id.id,
		}
		
		
		for rec in self.line_ids:
			debit_line = (0, 0, {
				'name': (_('%s of %s:%s') %(self.name, rec.employee_id.code,rec.employee_id.name)),
				'date': self.date or timenow,
				'account_id': self.expense_account.id,
				'journal_id': self.journal_id.id,
				'debit': rec.amount,
				'credit': 0.0,                    
				})
			
			number = 0
			nd_ids = self.expense_account.nd_ids
			if nd_ids:
				for auto_entry in auto_entries:
					if auto_entry.dimension_id in nd_ids:
						debit_line[2].update({auto_entry.dst_col.name : eval(auto_entry.src_fnc)})
						ans = self.env['analytic.structure'].search([('model_name','=','account_move_line'),('nd_id','=',auto_entry.dimension_id.id)])	
						number += math.pow(2,int(ans.ordering)-1)			
				debit_line[2].update({'d_bin' : bin(int(number))[2:].zfill(10)})
				
			move_lines.append(debit_line)
			
			
			credit_line = (0, 0, {
				'name': (_('%s of %s:%s') %(self.name, rec.employee_id.code,rec.employee_id.name)),
				'date': self.date or timenow,
				'journal_id': self.journal_id.id,
				'account_id': self.salary_payable_account.id,
				'debit': 0.0,
				'credit': rec.amount,                 
				})
			
			number = 0
			nd_ids = self.salary_payable_account.nd_ids
			if nd_ids:
				for auto_entry in auto_entries:
					if auto_entry.dimension_id in nd_ids:
						credit_line[2].update({auto_entry.dst_col.name : eval(auto_entry.src_fnc)})
						ans = self.env['analytic.structure'].search([('model_name','=','account_move_line'),('nd_id','=',auto_entry.dimension_id.id)])	
						number += math.pow(2,int(ans.ordering)-1)			
				credit_line[2].update({'d_bin' : bin(int(number))[2:].zfill(10)})
				
			move_lines.append(credit_line)
		
		
		move.update({'line_ids': move_lines})
		move = move_obj.create(move)
		self.write({'move_id': move.id, 'state': 'paid'})			
		move.post()
class RequestWizardStopWork(models.TransientModel):
    _name = 'request.wizard.stop.work'
    _description = 'Request Wizard: Stop Work'

    timesheet_line_id = fields.Many2one(
        'request.timesheet.line', required=True)
    date_start = fields.Datetime(
        related='timesheet_line_id.date_start', readonly=True)
    request_id = fields.Many2one(
        'request.request', related='timesheet_line_id.request_id',
        readonly=True)
    request_type_id = fields.Many2one(
        'request.type', related='timesheet_line_id.request_id.type_id',
        readonly=True, string="Request Type")
    request_text_sample = fields.Text(
        related='timesheet_line_id.request_id.request_text_sample',
        readonly=True)
    activity_id = fields.Many2one(
        'request.timesheet.activity', required=True, ondelete='cascade')
    amount = fields.Float(required=True)
    description = fields.Text()

    @api.model
    def default_get(self, fields_list):
        res = super(RequestWizardStopWork, self).default_get(fields_list)

        if res.get('timesheet_line_id') and 'amount' in fields_list:
            line = self.env['request.timesheet.line'].browse(
                res['timesheet_line_id'])
            start = fields.Datetime.from_string(line.date_start)
            end = fields.Datetime.from_string(fields.Datetime.now())
            amount_seconds = (end - start).total_seconds()

            if amount_seconds <= 60:
                # Ensure minimal amount is 1 minute
                amount_seconds = 61

            res.update({
                'amount': amount_seconds / 3600,
            })

        return res

    def _prepare_timesheet_line_data(self):
        return {
            'amount': self.amount,
            'activity_id': self.activity_id.id,
            'description': self.description,
        }

    def do_stop_work(self):
        self.ensure_one()

        self.timesheet_line_id.write(
            self._prepare_timesheet_line_data()
        )
        self.request_id.trigger_event('timetracking-stop-work', {
            'timesheet_line_id': self.timesheet_line_id.id,
        })

        if self.env.context.get('request_timesheet_start_request_id'):
            self.env['request.request'].browse(
                self.env.context.get('request_timesheet_start_request_id')
            ).action_start_work()
Exemple #13
0
class StockMove(models.Model):
    _inherit = 'stock.move'

    kardex_price_unit = fields.Float(string='Kardex Price Unit',
                                     default=0)  # digits=(total, decimal)
    type_operation_sunat_id = fields.Many2one('type.operation.kardex',
                                              'Tipo de Transacción')
    valoracion = fields.One2many(comodel_name='stock.valuation.layer',
                                 inverse_name='stock_move_id',
                                 string='Valoracion')

    def set_kardex_price_unit(self):
        total = 0
        for item in self.valoracion:
            total += item.value
        self.kardex_price_unit = total / (self.product_qty +
                                          0.0000000000000000000000000001)
        self.kardex_price_unit = self.kardex_price_unit - self.price_unit

    def _create_in_svl(self, forced_quantity=None):
        res = super(StockMove, self)._create_in_svl()
        for valuation in res:
            # Si existen ajustes de inventario inicial
            if valuation.stock_move_id.inventory_id:
                for line in valuation.stock_move_id.inventory_id.line_ids:
                    if line.product_id == valuation.product_id and line.location_id == valuation.stock_move_id.location_dest_id and line.is_initial:
                        valuation.update({
                            'unit_cost':
                            line.initial_cost,
                            'value':
                            line.initial_cost * valuation.quantity,
                            'remaining_value':
                            line.initial_cost * valuation.quantity
                        })
                        line.product_id.standard_price = line.initial_cost
            else:
                if valuation.stock_move_id.purchase_line_id:
                    price_unit = valuation.stock_move_id.purchase_line_id.price_unit
                else:
                    if valuation.stock_move_id.origin_returned_move_id:
                        vl = self.env['stock.valuation.layer'].search([
                            ('stock_move_id', '=',
                             valuation.stock_move_id.origin_returned_move_id.id
                             ),
                            ('product_id', '=',
                             valuation.stock_move_id.product_id.id)
                        ])
                        price_unit = vl.unit_cost
                    else:
                        # TODO pensar como hacer para mover productos de una almacen a otro
                        # que pueden tener costo valorizados distintos
                        price_unit = valuation.stock_move_id.product_id.standard_price
                if valuation.stock_move_id.purchase_line_id.currency_id and valuation.stock_move_id.purchase_line_id.currency_id != self.env.user.company_id.currency_id:
                    rate = valuation.currency_id._get_conversion_rate(
                        valuation.stock_move_id.purchase_line_id.currency_id,
                        self.env.user.company_id.currency_id,
                        self.env.user.company_id,
                        valuation.stock_move_id.picking_id.kardex_date
                        if valuation.stock_move_id.picking_id.use_kardex_date
                        else valuation.stock_move_id.picking_id.scheduled_date)
                    if valuation.stock_move_id.picking_id.invoice_id:  # or valuation.stock_move_id.picking_id.invoice_id_purchase:
                        # if valuation.stock_move_id.picking_id.invoice_id:
                        if valuation.stock_move_id.picking_id.invoice_id.tc_per:
                            price_unit = price_unit * valuation.stock_move_id.picking_id.invoice_id.currency_rate
                        else:
                            price_unit = price_unit * rate
                    else:
                        price_unit = price_unit * rate
                valuation.update({
                    'unit_cost':
                    price_unit,
                    'value':
                    price_unit * valuation.quantity,
                    'remaining_value':
                    price_unit * valuation.quantity
                })
        return res
Exemple #14
0
class ProductKardexLine(models.TransientModel):
    _name = "product.product.kardex.line"

    template = fields.Many2one(comodel_name='product.template',
                               string='template')

    name = fields.Many2one(comodel_name='product.product', string='Producto')
    type_operation_sunat_id = fields.Many2one('type.operation.kardex',
                                              'Tipo de Transacción')

    fecha = fields.Date(string='Fecha')

    cantidad_inicial = fields.Float(string='Cantidad Incial')
    costo_intradas = fields.Float(string='Costo de Inicial')
    total_bolivares_inicial = fields.Float(string='Total Bolivares Inicial')

    category_id = fields.Many2one(comodel_name='product.category',
                                  string='Categoria')

    cantidad_entradas = fields.Float(string='Cantidad Entradas')
    costo_entradas = fields.Float(string='Costo de Entradas')
    total_bolivares_entradas = fields.Float(string='Total Bolivares ')

    cantidad_salidas = fields.Float(string='Cantidad Salidas')
    costo_salidas = fields.Float(string='Costo de Salidas')
    total_bolivares_salida = fields.Float(string='Total Bolivares')

    total = fields.Float(string='Total')
    promedio = fields.Float(string='Promedio')
    total_bolivares = fields.Float(string='Total Bolivares')
class ResCurrency(models.Model):
    _inherit = 'res.currency.rate'

    rate = fields.Float(digits=dp.get_precision('Rate Precision'))
class MakingCharges(models.Model):
    _name = 'making.charges'
    _description = 'Making Charges'

    name = fields.Char('Name')
    making_charge = fields.Float('Charges')
Exemple #17
0
class ResCompanyProperty(models.Model):
    """
    We dont use res.company because most user dont' have access rights to edit
    it
    """
    _name = "res.company.property"
    _description = "Company Property"
    _auto = False
    # _rec_name = 'display_name'
    _depends = {
        'res.company': [
            'id',
        ],
    }

    company_id = fields.Many2one(
        'res.company',
        'Company',
        required=True,
    )

    @api.model_cr
    def init(self):
        cr = self._cr
        tools.drop_view_if_exists(cr, self._table)
        query = """
            SELECT
                c.id as id,
                c.id as company_id
            FROM
                res_company c
        """
        cr.execute("""CREATE or REPLACE VIEW %s as (%s
        )""" % (self._table, query))

    property_field = fields.Char(compute='_compute_property_field', )
    property_account_id = fields.Many2one(
        'account.account',
        string='Account',
        compute='_compute_property_account',
        inverse='_inverse_property_account',
    )
    property_term_id = fields.Many2one(
        'account.payment.term',
        string='Payment Term',
        compute='_compute_property_term',
        inverse='_inverse_property_term',
    )
    property_position_id = fields.Many2one(
        'account.fiscal.position',
        string='Fiscal Position',
        compute='_compute_property_position',
        inverse='_inverse_property_position',
    )
    standard_price = fields.Float(
        string="standard_price",
        compute='_compute_property_standard_price',
        inverse='_inverse_property_standard_price',
        digits=dp.get_precision('Product Price'),
    )
    # display_name = fields.Char(
    #     compute='_compute_display_name'
    # )

    @api.model
    def _get_companies(self):
        domain = []
        comodel = self._get_property_comodel()
        if comodel in ['account.account']:
            domain = [('company_id.consolidation_company', '=', False)]
        return self.search(domain)

    @api.model
    def action_company_properties(self):
        property_field = self._context.get('property_field', False)
        if not property_field:
            return True

        company_properties = self._get_companies()
        action = self.env.ref(
            'account_multicompany_ux.action_res_company_property')

        if not action:
            return False
        action_read = action.read()[0]
        # do this because raise an error if came from a view
        #  with group_by activated
        ctx = self._context.copy()
        ctx.pop('group_by', None)
        action_read['context'] = ctx
        action_read['domain'] = [('id', 'in', company_properties.ids)]
        return action_read

    @api.model
    def _get_property_comodel(self):
        property_field = self._context.get('property_field')
        record = self._get_record()
        if record:
            field = self._get_record()._fields.get(property_field)
            return field and field.comodel_name or False

    @api.model
    def _get_record(self):
        context = self._context
        active_model = context.get('active_model')
        active_id = context.get('active_id')
        property_field = context.get('property_field')
        if not property_field or not active_id or not active_model:
            _logger.warn('Could not get property record from context %s' %
                         context)
            return False
        return self.with_context(
            force_company=self.id).env[active_model].browse(active_id)

    @api.model
    def fields_view_get(self,
                        view_id=None,
                        view_type='form',
                        toolbar=False,
                        submenu=False):
        """
        Con esta funcion hacemos dos cosas:
        1. Mostrar solo la columna que corresponda segun el modelo
        2. Agregar dominio segun el dominio original de la porperty mas de cia
        """
        res = super(ResCompanyProperty,
                    self).fields_view_get(view_id=view_id,
                                          view_type=view_type,
                                          toolbar=toolbar,
                                          submenu=submenu)
        doc = etree.XML(res['arch'])
        property_field = self._context.get('property_field')
        domain = self._context.get('property_domain')
        record = self._get_record()
        if record:
            field = self._get_record()._fields.get(property_field)
            # si no viene definido un property_domain buscamos uno para
            # definido en el campo de la property
            if not domain:
                try:
                    domain = literal_eval(field.domain)
                except:
                    domain = []
            domain_elements = [str(x) for x in domain]

            # add company domain if comodel has company
            comodel = self._get_property_comodel()
            if comodel:
                if self.env[comodel]._fields.get('company_id'):
                    domain_elements += [
                        "'|'", "('company_id', '=', False)",
                        "('company_id', '=', company_id)"
                    ]
            str_domain = '[%s]' % ','.join(domain_elements)

            company_property_field = self._get_company_property_field()
            xpath = "//field[@name='%s']" % company_property_field
            for node in doc.xpath(xpath):
                node.set('domain', str(str_domain))
                node.set('invisible', '0')
                # modifiers make still invisible = 1
                setup_modifiers(node, res['fields'][company_property_field])
        res['arch'] = etree.tostring(doc)
        return res

    @api.model
    def _get_company_property_field(self):
        comodel = self._get_property_comodel()
        if comodel == 'account.account':
            company_property_field = 'property_account_id'
        elif comodel == 'account.fiscal.position':
            company_property_field = 'property_position_id'
        elif comodel == 'account.payment.term':
            company_property_field = 'property_term_id'
        else:
            property_field = self._context.get('property_field')
            if property_field == 'standard_price':
                company_property_field = 'standard_price'
            else:
                raise Warning(
                    _('Property for model %s not implemented yet' % comodel))
        return company_property_field

    @api.multi
    def name_get(self):
        """
        No llamamos a super porque tendriamos que igualmente hacer un read
        para obtener la compania y no queremos disminuir la performance
        """
        # por ahora en campos calculados no podemos cambiar el contexto de esta
        # manera
        # for rec in self.with_context(no_company_sufix=True):
        res = []
        for rec in self:
            company_field = getattr(rec.with_context(no_company_sufix=True),
                                    rec._get_company_property_field())
            if type(company_field) is float:
                precision_digits = self.env['decimal.precision'].precision_get(
                    'Product Price')
                # por alguna razon el float_round no nos está funcionando
                # y usamos round directamente (por ej. para valor 42,66)
                company_field = company_field and round(
                    company_field, precision_digits)
                # company_field = company_field and float_round(
                #     company_field, precision_digits=precision_digits)
                display_name = '%s%s' % (company_field or _('None'),
                                         rec.company_id.get_company_sufix())
            else:
                display_name = '%s%s' % (company_field.display_name
                                         or _('None'),
                                         rec.company_id.get_company_sufix())
            res.append((rec.id, display_name))
        return res

    def _compute_property_field(self):
        for record in self:
            record.property_field = self._context.get('property_field', '')

    @api.multi
    def _get_property_value(self):
        self.ensure_one()
        property_field = self.property_field
        record = self._get_record()
        if not record or not property_field:
            return False
        return getattr(record, property_field)

    def _compute_property_standard_price(self):
        for record in self.filtered(
                lambda x: x.property_field == 'standard_price'):
            record.standard_price = record._get_property_value()

    def _compute_property_account(self):
        for record in self:
            if record._get_property_comodel() == 'account.account':
                record.property_account_id = record._get_property_value()

    def _compute_property_position(self):
        for record in self:
            if record._get_property_comodel() == 'account.fiscal.position':
                record.property_position_id = record._get_property_value()

    def _compute_property_term(self):
        for record in self:
            if record._get_property_comodel() == 'account.payment.term':
                record.property_term_id = record._get_property_value()

    @api.multi
    def _set_property_value(self, value):
        self.ensure_one()
        record = self._get_record()
        property_field = self.property_field
        if not record or not property_field:
            return True
        setattr(record, property_field, value)

    @api.multi
    def _inverse_property_account(self):
        for rec in self:
            rec._set_property_value(rec.property_account_id.id)

    @api.multi
    def _inverse_property_position(self):
        for rec in self:
            rec._set_property_value(rec.property_position_id.id)

    @api.multi
    def _inverse_property_term(self):
        for rec in self:
            rec._set_property_value(rec.property_term_id.id)

    @api.multi
    def _inverse_property_standard_price(self):
        for rec in self:
            rec._set_property_value(rec.standard_price)
Exemple #18
0
class TSTInheritPosOrder(models.Model):
    _inherit = "pos.order"

    employees_ids = fields.One2many("tst.table.employees","pos_order_id", string="Working Employees")
    car_id = fields.Many2one("user.cars", string="Selected Car")
    per_day_reading = fields.Float("Car Reading Per Days")
    current_reading = fields.Float("Current Reading")
    next_oil_change_km = fields.Float("Next Oil Change KM")
    next_oil_change_date = fields.Date("Next Oil Change Date")
    car_per_day_read_expect = fields.Integer("Expected Car Reading After KM")
    order_id = fields.Many2one("pos.order", string="POS Order")

    @api.model
    def create(self, values):
        if values.get('session_id'):
            # set name based on the sequence specified on the config
            session = self.env['pos.session'].browse(values['session_id'])
            values['name'] = session.config_id.sequence_id._next()
            values.setdefault('pricelist_id', session.config_id.pricelist_id.id)
        else:
            # fallback on any pos.order sequence
            values['name'] = self.env['ir.sequence'].next_by_code('pos.order')

        getCreate = super(TSTInheritPosOrder, self).create(values)
        reading = self.env['user.cars.readings'].browse(values['reading_id'])
        reading.pos_order_id = getCreate.id
        return getCreate

    @api.multi
    def get_pos_order(self, vals):
        html = ""
        if 'order_id' in vals:
            html = "<tr class='readings-order-table-row'><td colspan='6'><table class='sub-table-table' style='width:100%'>"
            html += "<tr><th class='text-center'>Product Name</th><th class='text-center'>Quantity</th></tr>"
            pos_order = self.env['pos.order'].browse(int(vals['order_id']))
            if pos_order:
                for line in pos_order.lines:
                    html += "<tr><td class='text-center'>"+ line.product_id.name +"</td><td class='text-center'>"+ str(line.qty) +"</td></tr>"
            html += "</table><tr><td>"
            return html
        if html == '':
            return False

    @api.model
    def _order_fields(self, ui_order):
        process_line = partial(self.env['pos.order.line']._order_line_fields)
        terms = []
        values = {}
        values['per_day_reading'] = ui_order.get('per_day_reading') or False
        values['current_reading'] = ui_order.get('current_reading') or False
        values['next_oil_change_km'] = ui_order.get('next_oil_change') or False
        values['next_oil_change_date'] = ui_order.get('next_oil_change_date') or False
        values['car_per_day_read_expect'] = ui_order.get('car_per_day_read_expect') or False
        values['car_id'] = ui_order.get('selected_car') or False
        values['pos_order_id'] = False
        reading_id = None
        if 'selected_employees' in ui_order:
            for emp in ui_order['selected_employees']:
                vals = {}
                vals['emp_id'] = emp
                terms.append((0, 0, vals))
            try:
                if values.get('car_id'):
                    if values.get('next_oil_change_date'):
                        try:
                            values['next_oil_change_date'] = parser.parse(values.get('next_oil_change_date'))
                            values['next_oil_change_date'] = values['next_oil_change_date'].date()
                            values['next_oil_change_date'] = str(values['next_oil_change_date'])
                        except:
                            pass
                    reading_id = self.env['user.cars.readings'].create(values)
                    cars_model = self.env['user.cars']
                    res = cars_model.search([('id', '=', values['car_id'])]).read()
                    if len(res):
                        res = res[0]
                        car_values = {}
                        field_count = 0
                        if not res.get('car_reading_per_day'):
                            if values.get('per_day_reading'):
                                car_values['car_reading_per_day'] = values['per_day_reading']
                                field_count += 1
                        if not res.get('oil_change_after_reading'):
                            if values.get('next_oil_change_date'):
                                car_values['oil_change_after_reading'] = values['next_oil_change_date']
                                field_count += 1
                        if field_count:
                            cars_model.write(car_values)
            except Exception as e:
                print (str(e))
                raise ValidationError(e)
        res = {
            'name': ui_order['name'],
            'user_id': ui_order['user_id'] or False,
            'session_id': ui_order['pos_session_id'],
            'lines': [process_line(l) for l in ui_order['lines']] if ui_order['lines'] else False,
            'pos_reference': ui_order['name'],
            'partner_id': ui_order['partner_id'] or False,
            'date_order': ui_order['creation_date'],
            'fiscal_position_id': ui_order['fiscal_position_id'],
            'employees_ids': terms,
            'amount_tax': ui_order.get('amount_tax') or False,
            'amount_total': ui_order.get('amount_total') or False,
            'amount_paid': ui_order.get('amount_paid') or False,
            'amount_return': ui_order.get('amount_return') or False,
            'car_id': values['car_id'],
            'per_day_reading': values['per_day_reading'],
            'current_reading': values['current_reading'],
            'car_per_day_read_expect': values['car_per_day_read_expect'],
            'next_oil_change_km': values['next_oil_change_km'],
            'next_oil_change_date': values['next_oil_change_date'],
            'reading_id': reading_id.id if reading_id else False
        }
        return res
Exemple #19
0
class PricelistItem(models.Model):
    _name = "product.pricelist.item"
    _description = "Pricelist item"
    _order = "applied_on, min_quantity desc, categ_id desc, id"

    product_tmpl_id = fields.Many2one(
        'product.template', 'Product Template', ondelete='cascade',
        help="Specify a template if this rule only applies to one product template. Keep empty otherwise.")
    product_id = fields.Many2one(
        'product.product', 'Product', ondelete='cascade',
        help="Specify a product if this rule only applies to one product. Keep empty otherwise.")
    categ_id = fields.Many2one(
        'product.category', 'Product Category', ondelete='cascade',
        help="Specify a product category if this rule only applies to products belonging to this category or its children categories. Keep empty otherwise.")
    min_quantity = fields.Integer(
        'Min. Quantity', default=1,
        help="For the rule to apply, bought/sold quantity must be greater "
             "than or equal to the minimum quantity specified in this field.\n"
             "Expressed in the default unit of measure of the product.")
    applied_on = fields.Selection([
        ('3_global', 'Global'),
        ('2_product_category', ' Product Category'),
        ('1_product', 'Product'),
        ('0_product_variant', 'Product Variant')], "Apply On",
        default='3_global', required=True,
        help='Pricelist Item applicable on selected option')
    sequence = fields.Integer(
        'Sequence', default=5, required=True,
        help="Gives the order in which the pricelist items will be checked. The evaluation gives highest priority to lowest sequence and stops as soon as a matching item is found.")
    base = fields.Selection([
        ('list_price', 'Public Price'),
        ('standard_price', 'Cost'),
        ('pricelist', 'Other Pricelist')], "Based on",
        default='list_price', required=True,
        help='Base price for computation.\n'
             'Public Price: The base price will be the Sale/public Price.\n'
             'Cost Price : The base price will be the cost price.\n'
             'Other Pricelist : Computation of the base price based on another Pricelist.')
    base_pricelist_id = fields.Many2one('product.pricelist', 'Other Pricelist')
    pricelist_id = fields.Many2one('product.pricelist', 'Pricelist', index=True, ondelete='cascade')
    price_surcharge = fields.Float(
        'Price Surcharge', digits=dp.get_precision('Product Price'),
        help='Specify the fixed amount to add or substract(if negative) to the amount calculated with the discount.')
    price_discount = fields.Float('Price Discount', default=0, digits=(16, 2))
    price_round = fields.Float(
        'Price Rounding', digits=dp.get_precision('Product Price'),
        help="Sets the price so that it is a multiple of this value.\n"
             "Rounding is applied after the discount and before the surcharge.\n"
             "To have prices that end in 9.99, set rounding 10, surcharge -0.01")
    price_min_margin = fields.Float(
        'Min. Price Margin', digits=dp.get_precision('Product Price'),
        help='Specify the minimum amount of margin over the base price.')
    price_max_margin = fields.Float(
        'Max. Price Margin', digits=dp.get_precision('Product Price'),
        help='Specify the maximum amount of margin over the base price.')
    company_id = fields.Many2one(
        'res.company', 'Company',
        readonly=True, related='pricelist_id.company_id', store=True)
    currency_id = fields.Many2one(
        'res.currency', 'Currency',
        readonly=True, related='pricelist_id.currency_id', store=True)
    date_start = fields.Date('Start Date', help="Starting date for the pricelist item validation")
    date_end = fields.Date('End Date', help="Ending valid for the pricelist item validation")
    compute_price = fields.Selection([
        ('fixed', 'Fix Price'),
        ('percentage', 'Percentage (discount)'),
        ('formula', 'Formula')], index=True, default='fixed')
    fixed_price = fields.Float('Fixed Price', digits=dp.get_precision('Product Price'))
    percent_price = fields.Float('Percentage Price')
    # functional fields used for usability purposes
    name = fields.Char(
        'Name', compute='_get_pricelist_item_name_price',
        help="Explicit rule name for this pricelist line.")
    price = fields.Char(
        'Price', compute='_get_pricelist_item_name_price',
        help="Explicit rule name for this pricelist line.")

    @api.constrains('base_pricelist_id', 'pricelist_id', 'base')
    def _check_recursion(self):
        if any(item.base == 'pricelist' and item.pricelist_id and item.pricelist_id == item.base_pricelist_id for item in self):
            raise ValidationError(_('Error! You cannot assign the Main Pricelist as Other Pricelist in PriceList Item!'))
        return True

    @api.constrains('price_min_margin', 'price_max_margin')
    def _check_margin(self):
        if any(item.price_min_margin > item.price_max_margin for item in self):
            raise ValidationError(_('Error! The minimum margin should be lower than the maximum margin.'))
        return True

    @api.one
    @api.depends('categ_id', 'product_tmpl_id', 'product_id', 'compute_price', 'fixed_price', \
        'pricelist_id', 'percent_price', 'price_discount', 'price_surcharge')
    def _get_pricelist_item_name_price(self):
        if self.categ_id:
            self.name = _("Category: %s") % (self.categ_id.name)
        elif self.product_tmpl_id:
            self.name = self.product_tmpl_id.name
        elif self.product_id:
            self.name = self.product_id.display_name.replace('[%s]' % self.product_id.code, '')
        else:
            self.name = _("All Products")

        if self.compute_price == 'fixed':
            self.price = ("%s %s") % (self.fixed_price, self.pricelist_id.currency_id.name)
        elif self.compute_price == 'percentage':
            self.price = _("%s %% discount") % (self.percent_price)
        else:
            self.price = _("%s %% discount and %s surcharge") % (abs(self.price_discount), self.price_surcharge)

    @api.onchange('applied_on')
    def _onchange_applied_on(self):
        if self.applied_on != '0_product_variant':
            self.product_id = False
        if self.applied_on != '1_product':
            self.product_tmpl_id = False
        if self.applied_on != '2_product_category':
            self.categ_id = False

    @api.onchange('compute_price')
    def _onchange_compute_price(self):
        if self.compute_price != 'fixed':
            self.fixed_price = 0.0
        if self.compute_price != 'percentage':
            self.percent_price = 0.0
        if self.compute_price != 'formula':
            self.update({
                'price_discount': 0.0,
                'price_surcharge': 0.0,
                'price_round': 0.0,
                'price_min_margin': 0.0,
                'price_max_margin': 0.0,
            })
class LunchOrder(models.Model):
    _name = 'lunch.order'
    _description = 'Lunch Order'
    _order = 'id desc'
    _display_name = 'product_id'

    name = fields.Char(related='product_id.name',
                       string="Product Name",
                       readonly=True)  # to remove
    topping_ids_1 = fields.Many2many('lunch.topping',
                                     'lunch_order_topping',
                                     'order_id',
                                     'topping_id',
                                     string='Extras 1',
                                     domain=[('topping_category', '=', 1)])
    topping_ids_2 = fields.Many2many('lunch.topping',
                                     'lunch_order_topping',
                                     'order_id',
                                     'topping_id',
                                     string='Extras 2',
                                     domain=[('topping_category', '=', 2)])
    topping_ids_3 = fields.Many2many('lunch.topping',
                                     'lunch_order_topping',
                                     'order_id',
                                     'topping_id',
                                     string='Extras 3',
                                     domain=[('topping_category', '=', 3)])
    product_id = fields.Many2one('lunch.product',
                                 string="Product",
                                 required=True)
    category_id = fields.Many2one(string='Product Category',
                                  related='product_id.category_id',
                                  store=True)
    date = fields.Date('Order Date',
                       required=True,
                       readonly=True,
                       states={'new': [('readonly', False)]},
                       default=fields.Date.context_today)
    supplier_id = fields.Many2one(string='Vendor',
                                  related='product_id.supplier_id',
                                  store=True,
                                  index=True)
    user_id = fields.Many2one('res.users',
                              'User',
                              readonly=True,
                              states={'new': [('readonly', False)]},
                              default=lambda self: self.env.uid)
    note = fields.Text('Notes')
    price = fields.Float('Total Price',
                         compute='_compute_total_price',
                         readonly=True,
                         store=True,
                         digits='Account')
    active = fields.Boolean('Active', default=True)
    state = fields.Selection([('new', 'To Order'), ('ordered', 'Ordered'),
                              ('confirmed', 'Received'),
                              ('cancelled', 'Cancelled')],
                             'Status',
                             readonly=True,
                             index=True,
                             default='new')
    company_id = fields.Many2one('res.company',
                                 default=lambda self: self.env.company.id)
    currency_id = fields.Many2one(related='company_id.currency_id', store=True)
    quantity = fields.Float('Quantity', required=True, default=1)

    display_toppings = fields.Text('Extras',
                                   compute='_compute_display_toppings',
                                   store=True)

    product_description = fields.Text('Description',
                                      related='product_id.description')
    topping_label_1 = fields.Char(
        related='product_id.category_id.topping_label_1')
    topping_label_2 = fields.Char(
        related='product_id.category_id.topping_label_2')
    topping_label_3 = fields.Char(
        related='product_id.category_id.topping_label_3')
    topping_quantity_1 = fields.Selection(
        related='product_id.category_id.topping_quantity_1')
    topping_quantity_2 = fields.Selection(
        related='product_id.category_id.topping_quantity_2')
    topping_quantity_3 = fields.Selection(
        related='product_id.category_id.topping_quantity_3')
    image_1920 = fields.Image(compute='_compute_product_images')
    image_128 = fields.Image(compute='_compute_product_images')

    available_toppings_1 = fields.Boolean(
        help='Are extras available for this product',
        compute='_compute_available_toppings')
    available_toppings_2 = fields.Boolean(
        help='Are extras available for this product',
        compute='_compute_available_toppings')
    available_toppings_3 = fields.Boolean(
        help='Are extras available for this product',
        compute='_compute_available_toppings')

    @api.depends('product_id')
    def _compute_product_images(self):
        for line in self:
            line.image_1920 = line.product_id.image_1920 or line.category_id.image_1920
            line.image_128 = line.product_id.image_128 or line.category_id.image_128

    @api.depends('category_id')
    def _compute_available_toppings(self):
        for line in self:
            line.available_toppings_1 = bool(
                line.env['lunch.topping'].search_count([
                    ('category_id', '=', line.category_id.id),
                    ('topping_category', '=', 1)
                ]))
            line.available_toppings_2 = bool(
                line.env['lunch.topping'].search_count([
                    ('category_id', '=', line.category_id.id),
                    ('topping_category', '=', 2)
                ]))
            line.available_toppings_3 = bool(
                line.env['lunch.topping'].search_count([
                    ('category_id', '=', line.category_id.id),
                    ('topping_category', '=', 3)
                ]))

    def init(self):
        self._cr.execute(
            """CREATE INDEX IF NOT EXISTS lunch_order_user_product_date ON %s (user_id, product_id, date)"""
            % self._table)

    def _extract_toppings(self, values):
        """
            If called in api.multi then it will pop topping_ids_1,2,3 from values
        """
        if self.ids:
            # TODO This is not taking into account all the toppings for each individual order, this is usually not a problem
            # since in the interface you usually don't update more than one order at a time but this is a bug nonetheless
            topping_1 = values.pop('topping_ids_1')[0][
                2] if 'topping_ids_1' in values else self[:1].topping_ids_1.ids
            topping_2 = values.pop('topping_ids_2')[0][
                2] if 'topping_ids_2' in values else self[:1].topping_ids_2.ids
            topping_3 = values.pop('topping_ids_3')[0][
                2] if 'topping_ids_3' in values else self[:1].topping_ids_3.ids
        else:
            topping_1 = values['topping_ids_1'][0][
                2] if 'topping_ids_1' in values else []
            topping_2 = values['topping_ids_2'][0][
                2] if 'topping_ids_2' in values else []
            topping_3 = values['topping_ids_3'][0][
                2] if 'topping_ids_3' in values else []

        return topping_1 + topping_2 + topping_3

    @api.constrains('topping_ids_1', 'topping_ids_2', 'topping_ids_3')
    def _check_topping_quantity(self):
        errors = {
            '1_more': _('You should order at least one %s'),
            '1': _('You have to order one and only one %s'),
        }
        for line in self:
            for index in range(1, 4):
                availability = line['available_toppings_%s' % index]
                quantity = line['topping_quantity_%s' % index]
                toppings = line['topping_ids_%s' % index].filtered(
                    lambda x: x.topping_category == index)
                label = line['topping_label_%s' % index]

                if availability and quantity != '0_more':
                    check = bool(
                        len(toppings) == 1 if quantity == '1' else toppings)
                    if not check:
                        raise ValidationError(errors[quantity] % label)

    @api.model
    def create(self, values):
        lines = self._find_matching_lines({
            **values,
            'toppings':
            self._extract_toppings(values),
        })
        if lines:
            # YTI FIXME This will update multiple lines in the case there are multiple
            # matching lines which should not happen through the interface
            lines.update_quantity(1)
            return lines[:1]
        return super().create(values)

    def write(self, values):
        merge_needed = 'note' in values or 'topping_ids_1' in values or 'topping_ids_2' in values or 'topping_ids_3' in values

        if merge_needed:
            lines_to_deactivate = self.env['lunch.order']
            for line in self:
                # Only write on topping_ids_1 because they all share the same table
                # and we don't want to remove all the records
                # _extract_toppings will pop topping_ids_1, topping_ids_2 and topping_ids_3 from values
                # This also forces us to invalidate the cache for topping_ids_2 and topping_ids_3 that
                # could have changed through topping_ids_1 without the cache knowing about it
                toppings = self._extract_toppings(values)
                self.invalidate_cache(['topping_ids_2', 'topping_ids_3'])
                values['topping_ids_1'] = [(6, 0, toppings)]
                matching_lines = self._find_matching_lines({
                    'user_id':
                    values.get('user_id', line.user_id.id),
                    'product_id':
                    values.get('product_id', line.product_id.id),
                    'note':
                    values.get('note', line.note or False),
                    'toppings':
                    toppings,
                })
                if matching_lines:
                    lines_to_deactivate |= line
                    # YTI TODO Try to batch it, be careful there might be multiple matching
                    # lines for the same order hence quantity should not always be
                    # line.quantity, but rather a sum
                    matching_lines.update_quantity(line.quantity)
            lines_to_deactivate.write({'active': False})
            return super(LunchOrder, self - lines_to_deactivate).write(values)
        return super().write(values)

    @api.model
    def _find_matching_lines(self, values):
        domain = [
            ('user_id', '=',
             values.get('user_id',
                        self.default_get(['user_id'])['user_id'])),
            ('product_id', '=', values.get('product_id', False)),
            ('date', '=', fields.Date.today()),
            ('note', '=', values.get('note', False)),
        ]
        toppings = values.get('toppings', [])
        return self.search(domain).filtered(
            lambda line: (line.topping_ids_1 | line.topping_ids_2 | line.
                          topping_ids_3).ids == toppings)

    @api.depends('topping_ids_1', 'topping_ids_2', 'topping_ids_3',
                 'product_id', 'quantity')
    def _compute_total_price(self):
        for line in self:
            line.price = line.quantity * (line.product_id.price + sum(
                (line.topping_ids_1 | line.topping_ids_2
                 | line.topping_ids_3).mapped('price')))

    @api.depends('topping_ids_1', 'topping_ids_2', 'topping_ids_3')
    def _compute_display_toppings(self):
        for line in self:
            toppings = line.topping_ids_1 | line.topping_ids_2 | line.topping_ids_3
            line.display_toppings = ' + '.join(toppings.mapped('name'))

    def update_quantity(self, increment):
        for line in self.filtered(lambda line: line.state != 'confirmed'):
            if line.quantity <= -increment:
                # TODO: maybe unlink the order?
                line.active = False
            else:
                line.quantity += increment
        self._check_wallet()

    def add_to_cart(self):
        """
            This method currently does nothing, we currently need it in order to
            be able to reuse this model in place of a wizard
        """
        # YTI FIXME: Find a way to drop this.
        return True

    def _check_wallet(self):
        self.flush()
        for line in self:
            if self.env['lunch.cashmove'].get_wallet_balance(line.user_id) < 0:
                raise ValidationError(
                    _('Your wallet does not contain enough money to order that. To add some money to your wallet, please contact your lunch manager.'
                      ))

    def action_order(self):
        if self.filtered(lambda line: not line.product_id.active):
            raise ValidationError(_('Product is no longer available.'))
        self.write({'state': 'ordered'})
        self._check_wallet()

    def action_confirm(self):
        self.write({'state': 'confirmed'})

    def action_cancel(self):
        self.write({'state': 'cancelled'})
Exemple #21
0
class ProductTemplate(models.Model):
    _name = "product.template"
    _inherit = ['mail.thread']
    _description = "Product Template"
    _order = "name"

    def _get_default_category_id(self):
        if self._context.get('categ_id') or self._context.get('default_categ_id'):
            return self._context.get('categ_id') or self._context.get('default_categ_id')
        category = self.env.ref('product.product_category_all', raise_if_not_found=False)
        if not category:
            category = self.env['product.category'].search([], limit=1)
        if category:
            return category.id
        else:
            err_msg = _('You must define at least one product category in order to be able to create products.')
            redir_msg = _('Go to Internal Categories')
            raise RedirectWarning(err_msg, self.env.ref('product.product_category_action_form').id, redir_msg)

    def _get_default_uom_id(self):
        return self.env["product.uom"].search([], limit=1, order='id').id

    name = fields.Char('Name', index=True, required=True, translate=True)
    sequence = fields.Integer('Sequence', default=1, help='Gives the sequence order when displaying a product list')
    description = fields.Text(
        'Description', translate=True,
        help="A precise description of the Product, used only for internal information purposes.")
    description_purchase = fields.Text(
        'Purchase Description', translate=True,
        help="A description of the Product that you want to communicate to your vendors. "
             "This description will be copied to every Purchase Order, Receipt and Vendor Bill/Credit Note.")
    description_sale = fields.Text(
        'Sale Description', translate=True,
        help="A description of the Product that you want to communicate to your customers. "
             "This description will be copied to every Sales Order, Delivery Order and Customer Invoice/Credit Note")
    type = fields.Selection([
        ('consu', _('Consumable')),
        ('service', _('Service'))], string='Product Type', default='consu', required=True,
        help='A stockable product is a product for which you manage stock. The "Inventory" app has to be installed.\n'
             'A consumable product, on the other hand, is a product for which stock is not managed.\n'
             'A service is a non-material product you provide.\n'
             'A digital content is a non-material product you sell online. The files attached to the products are the one that are sold on '
             'the e-commerce such as e-books, music, pictures,... The "Digital Product" module has to be installed.')
    rental = fields.Boolean('Can be Rent')
    categ_id = fields.Many2one(
        'product.category', 'Internal Category',
        change_default=True, default=_get_default_category_id,
        required=True, help="Select category for the current product")

    currency_id = fields.Many2one(
        'res.currency', 'Currency', compute='_compute_currency_id')

    # price fields
    price = fields.Float(
        'Price', compute='_compute_template_price', inverse='_set_template_price',
        digits=dp.get_precision('Product Price'))
    list_price = fields.Float(
        'Sales Price', default=1.0,
        digits=dp.get_precision('Product Price'),
        help="Base price to compute the customer price. Sometimes called the catalog price.")
    lst_price = fields.Float(
        'Public Price', related='list_price',
        digits=dp.get_precision('Product Price'))
    standard_price = fields.Float(
        'Cost', compute='_compute_standard_price',
        inverse='_set_standard_price', search='_search_standard_price',
        digits=dp.get_precision('Product Price'), groups="base.group_user",
        help = "Cost used for stock valuation in standard price and as a first price to set in average/fifo. "
               "Also used as a base price for pricelists. "
               "Expressed in the default unit of measure of the product. ")

    volume = fields.Float(
        'Volume', compute='_compute_volume', inverse='_set_volume',
        help="The volume in m3.", store=True)
    weight = fields.Float(
        'Weight', compute='_compute_weight', digits=dp.get_precision('Stock Weight'),
        inverse='_set_weight', store=True,
        help="The weight of the contents in Kg, not including any packaging, etc.")

    sale_ok = fields.Boolean(
        'Can be Sold', default=True,
        help="Specify if the product can be selected in a sales order line.")
    purchase_ok = fields.Boolean('Can be Purchased', default=True)
    pricelist_id = fields.Many2one(
        'product.pricelist', 'Pricelist', store=False,
        help='Technical field. Used for searching on pricelists, not stored in database.')
    uom_id = fields.Many2one(
        'product.uom', 'Unit of Measure',
        default=_get_default_uom_id, required=True,
        help="Default Unit of Measure used for all stock operation.")
    uom_po_id = fields.Many2one(
        'product.uom', 'Purchase Unit of Measure',
        default=_get_default_uom_id, required=True,
        help="Default Unit of Measure used for purchase orders. It must be in the same category than the default unit of measure.")
    company_id = fields.Many2one(
        'res.company', 'Company',
        default=lambda self: self.env['res.company']._company_default_get('product.template'), index=1)
    packaging_ids = fields.One2many(
        'product.packaging', string="Product Packages", compute="_compute_packaging_ids", inverse="_set_packaging_ids",
        help="Gives the different ways to package the same product.")
    seller_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id', 'Vendors')
    variant_seller_ids = fields.One2many('product.supplierinfo', 'product_tmpl_id')

    active = fields.Boolean('Active', default=True, help="If unchecked, it will allow you to hide the product without removing it.")
    color = fields.Integer('Color Index')

    attribute_line_ids = fields.One2many('product.attribute.line', 'product_tmpl_id', 'Product Attributes')
    product_variant_ids = fields.One2many('product.product', 'product_tmpl_id', 'Products', required=True)
    # performance: product_variant_id provides prefetching on the first product variant only
    product_variant_id = fields.Many2one('product.product', 'Product', compute='_compute_product_variant_id')

    product_variant_count = fields.Integer(
        '# Product Variants', compute='_compute_product_variant_count')

    # related to display product product information if is_product_variant
    barcode = fields.Char('Barcode', oldname='ean13', related='product_variant_ids.barcode')
    default_code = fields.Char(
        'Internal Reference', compute='_compute_default_code',
        inverse='_set_default_code', store=True)

    item_ids = fields.One2many('product.pricelist.item', 'product_tmpl_id', 'Pricelist Items')

    # image: all image fields are base64 encoded and PIL-supported
    image = fields.Binary(
        "Image", attachment=True,
        help="This field holds the image used as image for the product, limited to 1024x1024px.")
    image_medium = fields.Binary(
        "Medium-sized image", attachment=True,
        help="Medium-sized image of the product. It is automatically "
             "resized as a 128x128px image, with aspect ratio preserved, "
             "only when the image exceeds one of those sizes. Use this field in form views or some kanban views.")
    image_small = fields.Binary(
        "Small-sized image", attachment=True,
        help="Small-sized image of the product. It is automatically "
             "resized as a 64x64px image, with aspect ratio preserved. "
             "Use this field anywhere a small image is required.")

    @api.depends('product_variant_ids')
    def _compute_product_variant_id(self):
        for p in self:
            p.product_variant_id = p.product_variant_ids[:1].id

    @api.multi
    def _compute_currency_id(self):
        try:
            main_company = self.sudo().env.ref('base.main_company')
        except ValueError:
            main_company = self.env['res.company'].sudo().search([], limit=1, order="id")
        for template in self:
            template.currency_id = template.company_id.sudo().currency_id.id or main_company.currency_id.id

    @api.multi
    def _compute_template_price(self):
        prices = {}
        pricelist_id_or_name = self._context.get('pricelist')
        if pricelist_id_or_name:
            pricelist = None
            partner = self._context.get('partner')
            quantity = self._context.get('quantity', 1.0)

            # Support context pricelists specified as display_name or ID for compatibility
            if isinstance(pricelist_id_or_name, pycompat.string_types):
                pricelist_data = self.env['product.pricelist'].name_search(pricelist_id_or_name, operator='=', limit=1)
                if pricelist_data:
                    pricelist = self.env['product.pricelist'].browse(pricelist_data[0][0])
            elif isinstance(pricelist_id_or_name, pycompat.integer_types):
                pricelist = self.env['product.pricelist'].browse(pricelist_id_or_name)

            if pricelist:
                quantities = [quantity] * len(self)
                partners = [partner] * len(self)
                prices = pricelist.get_products_price(self, quantities, partners)

        for template in self:
            template.price = prices.get(template.id, 0.0)

    @api.multi
    def _set_template_price(self):
        if self._context.get('uom'):
            for template in self:
                value = self.env['product.uom'].browse(self._context['uom'])._compute_price(template.price, template.uom_id)
                template.write({'list_price': value})
        else:
            self.write({'list_price': self.price})

    @api.depends('product_variant_ids', 'product_variant_ids.standard_price')
    def _compute_standard_price(self):
        unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1)
        for template in unique_variants:
            template.standard_price = template.product_variant_ids.standard_price
        for template in (self - unique_variants):
            template.standard_price = 0.0

    @api.one
    def _set_standard_price(self):
        if len(self.product_variant_ids) == 1:
            self.product_variant_ids.standard_price = self.standard_price

    def _search_standard_price(self, operator, value):
        products = self.env['product.product'].search([('standard_price', operator, value)], limit=None)
        return [('id', 'in', products.mapped('product_tmpl_id').ids)]

    @api.depends('product_variant_ids', 'product_variant_ids.volume')
    def _compute_volume(self):
        unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1)
        for template in unique_variants:
            template.volume = template.product_variant_ids.volume
        for template in (self - unique_variants):
            template.volume = 0.0

    @api.one
    def _set_volume(self):
        if len(self.product_variant_ids) == 1:
            self.product_variant_ids.volume = self.volume

    @api.depends('product_variant_ids', 'product_variant_ids.weight')
    def _compute_weight(self):
        unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1)
        for template in unique_variants:
            template.weight = template.product_variant_ids.weight
        for template in (self - unique_variants):
            template.weight = 0.0

    @api.one
    def _set_weight(self):
        if len(self.product_variant_ids) == 1:
            self.product_variant_ids.weight = self.weight

    @api.one
    @api.depends('product_variant_ids.product_tmpl_id')
    def _compute_product_variant_count(self):
        self.product_variant_count = len(self.product_variant_ids)

    @api.depends('product_variant_ids', 'product_variant_ids.default_code')
    def _compute_default_code(self):
        unique_variants = self.filtered(lambda template: len(template.product_variant_ids) == 1)
        for template in unique_variants:
            template.default_code = template.product_variant_ids.default_code
        for template in (self - unique_variants):
            template.default_code = ''

    @api.one
    def _set_default_code(self):
        if len(self.product_variant_ids) == 1:
            self.product_variant_ids.default_code = self.default_code

    @api.depends('product_variant_ids', 'product_variant_ids.packaging_ids')
    def _compute_packaging_ids(self):
        for p in self:
            if len(p.product_variant_ids) == 1:
                p.packaging_ids = p.product_variant_ids.packaging_ids

    def _set_packaging_ids(self):
        for p in self:
            if len(p.product_variant_ids) == 1:
                p.product_variant_ids.packaging_ids = p.packaging_ids

    @api.constrains('uom_id', 'uom_po_id')
    def _check_uom(self):
        if any(template.uom_id and template.uom_po_id and template.uom_id.category_id != template.uom_po_id.category_id for template in self):
            raise ValidationError(_('Error: The default Unit of Measure and the purchase Unit of Measure must be in the same category.'))
        return True

    @api.onchange('uom_id')
    def _onchange_uom_id(self):
        if self.uom_id:
            self.uom_po_id = self.uom_id.id

    @api.model
    def create(self, vals):
        ''' Store the initial standard price in order to be able to retrieve the cost of a product template for a given date'''
        # TDE FIXME: context brol
        tools.image_resize_images(vals)
        template = super(ProductTemplate, self).create(vals)
        if "create_product_product" not in self._context:
            template.with_context(create_from_tmpl=True).create_variant_ids()

        # This is needed to set given values to first variant after creation
        related_vals = {}
        if vals.get('barcode'):
            related_vals['barcode'] = vals['barcode']
        if vals.get('default_code'):
            related_vals['default_code'] = vals['default_code']
        if vals.get('standard_price'):
            related_vals['standard_price'] = vals['standard_price']
        if vals.get('volume'):
            related_vals['volume'] = vals['volume']
        if vals.get('weight'):
            related_vals['weight'] = vals['weight']
        if related_vals:
            template.write(related_vals)
        return template

    @api.multi
    def write(self, vals):
        tools.image_resize_images(vals)
        res = super(ProductTemplate, self).write(vals)
        if 'attribute_line_ids' in vals or vals.get('active'):
            self.create_variant_ids()
        if 'active' in vals and not vals.get('active'):
            self.with_context(active_test=False).mapped('product_variant_ids').write({'active': vals.get('active')})
        return res

    @api.multi
    def copy(self, default=None):
        # TDE FIXME: should probably be copy_data
        self.ensure_one()
        if default is None:
            default = {}
        if 'name' not in default:
            default['name'] = _("%s (copy)") % self.name
        return super(ProductTemplate, self).copy(default=default)

    @api.multi
    def name_get(self):
        return [(template.id, '%s%s' % (template.default_code and '[%s] ' % template.default_code or '', template.name))
                for template in self]

    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        # Only use the product.product heuristics if there is a search term and the domain
        # does not specify a match on `product.template` IDs.
        if not name or any(term[0] == 'id' for term in (args or [])):
            return super(ProductTemplate, self).name_search(name=name, args=args, operator=operator, limit=limit)

        Product = self.env['product.product']
        templates = self.browse([])
        while True:
            domain = templates and [('product_tmpl_id', 'not in', templates.ids)] or []
            args = args if args is not None else []
            products_ns = Product.name_search(name, args+domain, operator=operator)
            products = Product.browse([x[0] for x in products_ns])
            templates |= products.mapped('product_tmpl_id')
            if (not products) or (limit and (len(templates) > limit)):
                break

        # re-apply product.template order + name_get
        return super(ProductTemplate, self).name_search(
            '', args=[('id', 'in', list(set(templates.ids)))],
            operator='ilike', limit=limit)

    @api.multi
    def price_compute(self, price_type, uom=False, currency=False, company=False):
        # TDE FIXME: delegate to template or not ? fields are reencoded here ...
        # compatibility about context keys used a bit everywhere in the code
        if not uom and self._context.get('uom'):
            uom = self.env['product.uom'].browse(self._context['uom'])
        if not currency and self._context.get('currency'):
            currency = self.env['res.currency'].browse(self._context['currency'])

        templates = self
        if price_type == 'standard_price':
            # standard_price field can only be seen by users in base.group_user
            # Thus, in order to compute the sale price from the cost for users not in this group
            # We fetch the standard price as the superuser
            templates = self.with_context(force_company=company and company.id or self._context.get('force_company', self.env.user.company_id.id)).sudo()

        prices = dict.fromkeys(self.ids, 0.0)
        for template in templates:
            prices[template.id] = template[price_type] or 0.0

            if uom:
                prices[template.id] = template.uom_id._compute_price(prices[template.id], uom)

            # Convert from current user company currency to asked one
            # This is right cause a field cannot be in more than one currency
            if currency:
                prices[template.id] = template.currency_id.compute(prices[template.id], currency)

        return prices

    # compatibility to remove after v10 - DEPRECATED
    @api.model
    def _price_get(self, products, ptype='list_price'):
        return products.price_compute(ptype)

    @api.multi
    def create_variant_ids(self):
        Product = self.env["product.product"]
        AttributeValues = self.env['product.attribute.value']
        for tmpl_id in self.with_context(active_test=False):
            # adding an attribute with only one value should not recreate product
            # write this attribute on every product to make sure we don't lose them
            variant_alone = tmpl_id.attribute_line_ids.filtered(lambda line: len(line.value_ids) == 1).mapped('value_ids')
            for value_id in variant_alone:
                updated_products = tmpl_id.product_variant_ids.filtered(lambda product: value_id.attribute_id not in product.mapped('attribute_value_ids.attribute_id'))
                updated_products.write({'attribute_value_ids': [(4, value_id.id)]})

            # iterator of n-uple of product.attribute.value *ids*
            variant_matrix = [
                AttributeValues.browse(value_ids)
                for value_ids in itertools.product(*(line.value_ids.ids for line in tmpl_id.attribute_line_ids if line.value_ids[:1].attribute_id.create_variant))
            ]

            # get the value (id) sets of existing variants
            existing_variants = {frozenset(variant.attribute_value_ids.ids) for variant in tmpl_id.product_variant_ids}
            # -> for each value set, create a recordset of values to create a
            #    variant for if the value set isn't already a variant
            to_create_variants = [
                value_ids
                for value_ids in variant_matrix
                if set(value_ids.ids) not in existing_variants
            ]

            # check product
            variants_to_activate = self.env['product.product']
            variants_to_unlink = self.env['product.product']
            for product_id in tmpl_id.product_variant_ids:
                if not product_id.active and product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) in variant_matrix:
                    variants_to_activate |= product_id
                elif product_id.attribute_value_ids.filtered(lambda r: r.attribute_id.create_variant) not in variant_matrix:
                    variants_to_unlink |= product_id
            if variants_to_activate:
                variants_to_activate.write({'active': True})

            # create new product
            for variant_ids in to_create_variants:
                new_variant = Product.create({
                    'product_tmpl_id': tmpl_id.id,
                    'attribute_value_ids': [(6, 0, variant_ids.ids)]
                })

            # unlink or inactive product
            for variant in variants_to_unlink:
                try:
                    with self._cr.savepoint(), tools.mute_logger('odoo.sql_db'):
                        variant.unlink()
                # We catch all kind of exception to be sure that the operation doesn't fail.
                except (psycopg2.Error, except_orm):
                    variant.write({'active': False})
                    pass
        return True
class AASQualityRejectionWizard(models.TransientModel):
    _name = 'aas.quality.rejection.wizard'
    _description = 'AAS Quality Rejection Wizard'

    quality_id = fields.Many2one(comodel_name='aas.quality.order',
                                 string=u'质检单',
                                 ondelete='cascade')
    product_id = fields.Many2one(comodel_name='product.product',
                                 string=u'产品',
                                 ondelete='cascade')
    product_uom = fields.Many2one(comodel_name='product.uom',
                                  string=u'单位',
                                  ondelete='cascade')
    partner_id = fields.Many2one(comodel_name='res.partner',
                                 string=u'业务伙伴',
                                 ondelete='cascade')
    product_qty = fields.Float(
        string=u'数量',
        digits=dp.get_precision('Product Unit of Measure'),
        default=0.0)
    plot_lines = fields.One2many(
        comodel_name='aas.quality.rejection.lot.wizard',
        inverse_name='wizard_id',
        string=u'批次明细')
    label_lines = fields.One2many(
        comodel_name='aas.quality.rejection.label.wizard',
        inverse_name='wizard_id',
        string=u'标签明细')

    @api.one
    def action_check_lots(self):
        if not self.plot_lines or len(self.plot_lines) <= 0:
            raise UserError(u'您还没有添加批次拆分明细!')
        for plot in self.plot_lines:
            if float_compare(plot.label_qty, 0.0,
                             precision_rounding=0.000001) <= 0.0:
                raise UserError(u'批次%s拆分标签每标签的数量不能小于零' % plot.product_lot.name)
            if float_compare(plot.label_qty,
                             plot.product_qty,
                             precision_rounding=0.000001) > 0.0:
                raise UserError(u'批次%s拆分标签每标签的数量不能大于批次总数' %
                                plot.product_lot.name)

    @api.multi
    def action_split_lots(self):
        """
        批次拆分
        :return:
        """
        self.ensure_one()
        self.action_dolabels()
        view_form = self.env.ref(
            'aas_quality.view_form_aas_quality_rejection_labels_wizard')
        return {
            'name': u"不合格品标签",
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'aas.quality.rejection.wizard',
            'views': [(view_form.id, 'form')],
            'view_id': view_form.id,
            'target': 'new',
            'res_id': self.id,
            'context': self.env.context
        }

    @api.one
    def action_dolabels(self):
        self.action_check_lots()
        label_lines = []
        for plot in self.plot_lines:
            tproduct_qty, tlabel_qty = plot.product_qty, plot.label_qty
            for tindex in range(
                    int(math.ceil(plot.product_qty / plot.label_qty))):
                if float_compare(
                        tproduct_qty, 0.0, precision_rounding=0.000001) <= 0.0:
                    break
                if float_compare(tproduct_qty,
                                 plot.label_qty,
                                 precision_rounding=0.000001) < 0.0:
                    tlabel_qty = tproduct_qty
                label_lines.append((0, 0, {
                    'product_lot': plot.product_lot.id,
                    'label_qty': tlabel_qty,
                    'origin_order': plot.origin_order,
                    'commit_id': plot.commit_id,
                    'commit_model': plot.commit_model,
                    'commit_order': plot.commit_order
                }))
                tproduct_qty -= tlabel_qty
        self.write({'label_lines': label_lines})

    @api.one
    def action_done(self):
        rejection_lines = []
        templocation = self.env['stock.warehouse'].get_default_warehouse(
        ).wh_input_stock_loc_id
        for tline in self.label_lines:
            tempvals = {
                'product_id': self.product_id.id,
                'product_uom': self.product_uom.id,
                'partner_id': self.partner_id and self.partner_id.id
            }
            tempvals.update({
                'location_id': templocation.id,
                'product_lot': tline.product_lot.id,
                'product_qty': tline.label_qty,
                'origin_order': tline.origin_order,
                'locked': True,
                'locked_order': tline.commit_order,
                'stocked': True,
                'state': 'normal',
                'qualified': False
            })
            templabel = self.env['aas.product.label'].create(tempvals)
            rejection_lines.append((0, 0, {
                'label_id': templabel.id,
                'product_id': tempvals['product_id'],
                'product_uom': tempvals['product_uom'],
                'product_lot': tempvals['product_lot'],
                'product_qty': tempvals['product_qty'],
                'origin_order': tempvals['origin_order'],
                'current_label': True,
                'commit_id': tline.commit_id,
                'commit_model': tline.commit_model,
                'commit_order': tline.commit_order
            }))
        self.quality_id.write({'rejection_lines': rejection_lines})
        self.quality_id.action_quality_done()
Exemple #23
0
class Predict(models.Model):  
    _name =  'tsbd.predict'
    trig = fields.Boolean()
    match_state = fields.Char(related='match_id.state', store=True)
    match_id = fields.Many2one('tsbd.match')
    site_id = fields.Many2one('tsbd.site',string='web site')
    link = fields.Char()
    predict_score1 = fields.Integer()
    predict_score2 = fields.Integer()
    predict_handicap = fields.Selection([('handicap1','handicap1'),('handicap2','handicap2')],compute='predict_handicap_and_ou_',store=True)
    amount = fields.Float(default=1)
    predict_exact_score_winning_amount =  fields.Float(compute='predict_exact_score_winning_amount_',store=True)
    state =  fields.Selection([('nhap_tay',u'Nhập tay'),('tu_dong','Tự động'),('can_read_du_doan','Không đọc được dự đoán')],default = 'nhap_tay')
    
    time= fields.Datetime(related='match_id.time', store=True)
    date = fields.Date (related='match_id.date', store=True)
    
    team1= fields.Many2one('tsbd.team',related='match_id.team1', store=True)
    team2= fields.Many2one('tsbd.team',related='match_id.team2', store=True)
    begin_handicap =  fields.Float(digit=(6,2),related='match_id.begin_handicap', store=True)
    begin_ou=  fields.Float(digit=(6,2),related='match_id.begin_ou', store=True)
#     state_match = fields.Char(related = 'match_id.state',store=True)
    @api.onchange('link')
    def link_oc_(self):
        if self.link:
            rs = re.search('//(.+?)/',self.link)
            site_name = rs.group(1).replace('www.','')
            site_id = get_or_create_object_sosanh (self,'tsbd.site',{'name':site_name})
            self.site_id = site_id

    @api.depends('match_id.begin_ou','match_id.begin_handicap','predict_score1','predict_score2')
    def predict_handicap_and_ou_(self):
        for r in self:
            diff = (r.predict_score1 - r.predict_score2) - r.match_id.begin_handicap
            if diff > 0:
                predict_handicap = 'handicap1'
            else:
                predict_handicap = 'handicap2'
            r.predict_handicap = predict_handicap
            
            sum_score = r.predict_score1 + r.predict_score2
            if sum_score > r.match_id.begin_ou:
                predict_ou = 'over'
            else:
                predict_ou = 'under'
            r.predict_ou = predict_ou
    predict_ou = fields.Selection([('over','over'),('under','under')],compute='predict_handicap_and_ou_',store=True)
    predict_handicap_winning_mount = fields.Float(compute='predict_handicap_winning_mount_',store=True)
    predict_ou_winning_mount = fields.Float(compute='predict_ou_winning_mount_',store=True)
    
    
    @api.depends('predict_ou','trig', 'match_state')
    @adecorator
    def predict_ou_winning_mount_(self):
        for r in self:
            bet_kind = r.predict_ou
            winning_ratio,winning_amount = handicap_winning_(r,bet_kind,mode='predict')
            r.predict_ou_winning_mount = winning_amount
    
    @api.depends('predict_handicap','trig','match_state')
    @adecorator
    def predict_handicap_winning_mount_(self):
        for r in self:
            bet_kind = r.predict_handicap
            winning_ratio,winning_amount = handicap_winning_(r,bet_kind,mode='predict')
            r.predict_handicap_winning_mount = winning_amount
            
    @api.depends('predict_score1','predict_score2','trig','match_state')
    @adecorator
    def predict_exact_score_winning_amount_(self):
        for r in self:
            bet_kind = 'exact_score'
            winning_ratio,winning_amount = handicap_winning_(r,bet_kind,mode='predict')
            r.predict_exact_score_winning_amount = winning_amount
Exemple #24
0
class SRDCMixDesign(models.Model):
    _name = "srdc.mix.design"

    name = fields.Char()
    active = fields.Boolean(default=True)
    product_id = fields.Many2one('product.product')
    product_qty = fields.Float(default=1)
    sequence = fields.Integer()
    line_ids = fields.One2many('srdc.mix.design.line', 'mix_design_id', srting='Mix_Design')
    is_auto = fields.Boolean()
    total_amount = fields.Float(compute='_compute_total_amount', store=True)
    optimize_total_amount = fields.Float(compute='_compute_total_amount', store=True)
    is_standard = fields.Boolean('Standard?')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('confirmed', 'Confirmed'),
        ('lab_test', 'LAB Test'),
        ('validated', 'Validated'),
        ('done', 'Done'),
        ('pending', 'Pending'),
        ('cancel', 'Cancel'),
    ], default='draft')

    _sql_constraints = [
        ('name_uniq', 'unique (name)', "Code name already exists !"),
    ]

    @api.model
    def create(self, vals):
        if not self.search([('is_standard', '=', True)]) and not vals.get('is_standard'):
            vals['is_standard'] = True
        return super(SRDCMixDesign, self).create(vals)

    @api.model
    def default_get(self, fields):
        defaults = super(SRDCMixDesign, self).default_get(fields)
        material_ids = self.env['product.product'].search([
            ('categ_id.parent_id', '=', self.env.ref('srdc_qc.product_category_material').id)
        ], order='id')
        defaults['line_ids'] = [
            (0, 0, {
                'product_id': material.id,
                'product_tmpl_id': material.product_tmpl_id.id,
                'categ_id': material.categ_id.id,
                'quantity': 0,
                'sequence': material.id,
                'oum_id': material.uom_id.id
            }) for material in material_ids]
        return defaults

    @api.multi
    @api.depends('line_ids.quantity', 'line_ids.product_id', 'line_ids.product_id.standard_price',
                 'line_ids.supplierinfo_id', 'line_ids.supplierinfo_id.price')
    def _compute_total_amount(self):
        for rec in self:
            sum = 0
            optimize_sum = 0
            for line in rec.line_ids.filtered(
                    lambda l: l.quantity > 0 and (
                            l.product_id.standard_price > 0 or l.supplierinfo_id and l.supplierinfo_id.price > 0)):
                if line.supplierinfo_id:
                    sum += line.supplierinfo_id.price * line.quantity
                    optimize_sum += line.supplierinfo_id.optimize_price * line.quantity
                else:
                    sum += line.product_id.standard_price * line.quantity
                    optimize_sum += line.product_id.optimize_price * line.quantity
            rec.total_amount = sum
            rec.optimize_total_amount = optimize_sum

    @api.multi
    def btn_confirm(self):
        self.write({'state': 'confirmed'})

    @api.multi
    def btn_start_lab_test(self):
        self.write({'state': 'lab_test'})

    @api.multi
    def btn_validate(self):
        self.write({'state': 'validated'})

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

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

    @api.multi
    def btn_cancel(self):
        self.write({'state': 'cancel'})
Exemple #25
0
class CurrencyRate(models.Model):
    _inherit = "res.currency.rate"

    rate = fields.Float(
        digits=(12, 16),
        help='The rate of the currency to the currency of rate 1')
Exemple #26
0
class PR(models.Model):
    _name = 'pr.pr'
    _rec_name = 'name'
    name = fields.Char('Name')
    date_pr = fields.Datetime('PR Date', required=True)
    partner_id = fields.Many2one('res.partner', string='Vendor', required=True)
    project_id = fields.Many2one('pr.project', string='Project')
    approve_id = fields.Many2one('res.users', string='Approver')
    amount_untaxed = fields.Float(string='Untaxed Amount', store=True, readonly=True)
    amount_tax = fields.Float(string='Taxes', store=True, readonly=True)
    amount_total = fields.Float(string='Total', store=True, readonly=True)
    note = fields.Text('Note')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('revise', 'Revise'),
        ('approve', 'Approve'),
        ('cancel', 'Cancel'),
    ], string='Status', default='draft')
    pr_lines = fields.One2many('pr.pr_line', 'pr_id', string='PR Line')
    company_id = fields.Many2one('res.company', default=lambda self: self.env.user.company_id.id)

    def get_baht_text(self):
        return bahttext(self.amount_total)

    @api.model
    def create(self, vals):
        seq = self.env['ir.sequence'].next_by_code('pr.pr_num') or '-'
        vals['name'] = seq
        return super(PR, self).create(vals)

    @api.onchange('pr_lines')
    def get_total_amount(self):
        amount_untaxed = 0
        tax_rate = self.env.user.company_id.account_purchase_tax_id.amount or 7
        for r in self:
            for item in r.pr_lines:
                amount_untaxed += item.amount
        self.amount_untaxed = amount_untaxed
        self.amount_tax = (self.amount_untaxed * tax_rate) / 100
        self.amount_total = self.amount_untaxed + self.amount_tax

    def do_pr_draft(self):
        self.write({'state': 'draft'})

    def do_pr_approve(self):
        if not self.project_id.budget:
            raise exceptions.ValidationError(_('Project budget invalid amount!'))

        if self.amount_total > self.project_id.budget:
            raise exceptions.ValidationError(_('This PR is over budget!!'))

        self.create_rfq()
        self.write({'state': 'approve'})

    def create_rfq(self):
        rfq = self.env['purchase.order'].sudo().create({
            'partner_id': self.partner_id.id,
            'state': 'draft',
        })

        for line in self.pr_lines:
            rfq_line = self.env['purchase.order.line'].sudo().create({
                'order_id': rfq.id,
                'name': line.name,
                'product_id': line.product_id.id,
                'product_qty': line.qty,
                'product_uom': line.product_id.uom_id.id,
                'price_unit': line.price,
                'price_subtotal': line.amount,
                'date_planned': datetime.now(),
            })

    def do_pr_cancel(self):
        return {
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'pr.cancel.wizard',
            'target': 'new',
            'type': 'ir.actions.act_window',
            'context': {
                'default_pr_id': self.id,
                'default_pr_name': self.name,
            }
        }

    def do_add_products(self):
        return {
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'product.multi.wizard',
            'target': 'new',
            'type': 'ir.actions.act_window',
            'context': {
                'default_pr_id': self.id,
            }
        }
Exemple #27
0
class HrPayslip(models.Model):
    _name = 'hr.payslip'
    _inherit = ['mail.thread', 'hr.payslip']

    #added by sangita
    refund_id = fields.Many2one('hr.payslip', string="Refund ID")

    @api.model
    def _get_currency(self):
        return self.env.user.company_id.currency_id.id

    currency_id = fields.Many2one('res.currency',
                                  string='Currency',
                                  readonly=True,
                                  required=True,
                                  default=lambda self: self._get_currency())

    def compute_difference_two_date(self):
        s = datetime.strptime(self.date_from, "%Y-%m-%d")
        e = datetime.strptime(self.date_to, "%Y-%m-%d")
        start = s.day
        end = e.day
        date_days = end - start
        return date_days
#               deadline_days = (date.today() - deadline_date).days
#

    def convert_number2word_inv(self):
        for line in self.line_ids:
            if line.code == 'NET':
                return self.env['convert.num2word'].convert_number2word(
                    line.amount, 'en_US', self.currency_id.name)

    def leaves_type_cal_earned(self):
        earned = 0
        res = self.env['hr.holidays'].search([
            ('holiday_type', '=', 'employee'),
            ('holiday_status_id.limit', '=', False), ('state', '!=', 'refuse'),
            ('employee_id', '=', self.employee_id.id),
            ('earned_leaves', '=', True)
        ])
        for r in res:
            earned = r.number_of_days_temp
            return earned

    def leaves_type_cal_sick(self):
        sick = 0
        res = self.env['hr.holidays'].search([
            ('holiday_type', '=', 'employee'),
            ('holiday_status_id.limit', '=', False), ('state', '!=', 'refuse'),
            ('employee_id', '=', self.employee_id.id),
            ('sick_leaves', '=', True)
        ])
        for r in res:
            sick = r.number_of_days_temp
        return sick

    def leaves_type_cal_casual(self):
        casual = 0
        res = self.env['hr.holidays'].search([
            ('holiday_type', '=', 'employee'),
            ('holiday_status_id.limit', '=', False), ('state', '!=', 'refuse'),
            ('employee_id', '=', self.employee_id.id),
            ('casual_leaves', '=', True)
        ])
        for r in res:
            casual = r.number_of_days_temp
        return casual

    def unused_leaves_cal(self):
        unused = 0
        a = []
        unused_leaves_id = self.env['hr.holidays'].search([
            ('holiday_type', '=', 'employee'),
            ('employee_id', '=', self.employee_id.id), ('type', '=', 'add'),
            ('state', 'in', ('confirm', 'validate'))
        ])
        for i in unused_leaves_id:
            a += [i.number_of_days]
            unused = sum(a)
        return unused

    def used_leaves_cal(self):
        used = 0
        a = []
        used_leaves_id = self.env['hr.holidays'].search([
            ('holiday_type', '=', 'employee'),
            ('employee_id', '=', self.employee_id.id), ('type', '=', 'remove'),
            ('state', 'in', ('confirm', 'validate'))
        ])
        for i in used_leaves_id:
            a += [-i.number_of_days]
            used = sum(a)
        return used

    #added by sangita
    def compute_net_pay(self):
        loan_amount = 0.0
        if self.line_ids:
            for line in self.line_ids:
                if line.code == 'LOAN':
                    loan_amount = line.amount
                if line.code == 'NET':
                    net = line.amount - loan_amount
                    return net

    #added by sangita
    @api.multi
    @api.depends('employee_id', 'employee_id.leaves_count')
    def _compute_leaves_count(self):
        for t in self:
            for d in t.employee_id:
                t.leaves_count = d.leaves_count

    #akhodifad
    @api.constrains('date_from', 'date_to', 'employee_id')
    def _compute_ytd_count(self):
        for t in self:
            if t.employee_id:
                to_date = t.date_to.split("-")
                SQL = """
                    select ps.employee_id,
                    sum(psl.total)
                    from hr_payslip_line psl
                    inner join hr_payslip ps on ps.id=psl.slip_id
                    and extract(year from ps.date_to) = %s
                    and ps.employee_id = %s
                    and ps.company_id = %s
                    and code = 'NET'
                    group by ps.employee_id, ps.company_id;
                """
                self.env.cr.execute(SQL, (
                    int(to_date[0]),
                    t.employee_id.id,
                    t.company_id.id or None,
                ))
                res = self.env.cr.fetchall()
                if res:
                    t.ytd_count = float(res[0][1])

    def _get_cash_and_bank(self):
        type_id = False
        type_id = self.env.ref('account.data_account_type_liquidity').id
        return [('user_type_id', '=', type_id)]

    leaves_count = fields.Integer('Number of Leaves',
                                  compute='_compute_leaves_count')
    ytd_count = fields.Float('Number of YTD', compute='_compute_ytd_count')
    account_id = fields.Many2one('account.account',
                                 'Account',
                                 domain=_get_cash_and_bank)

    pay_odr_id = fields.Many2one('payment.order', string="Payment Order")

    #added by sangita
    @api.multi
    @api.onchange('contract_id')
    def onchange_contract(self):
        super(HrPayslip, self).onchange_contract()
        self.account_id = self.contract_id.account_id.id
#
#added by sangita

    @api.constrains('contract_id')
    def onchange_contract_to_account(self):
        self.account_id = self.contract_id.account_id.id

    @api.multi
    def create_account_voucher(self):
        ac_voucher = self.env['account.voucher']
        ac_exit = ac_voucher.search([('name', '=', self.name)])
        if self.paid:
            raise UserError(_('Payment Order already created.'))

        ac_vc_lin = self.env['account.voucher.line']
        vals_ac = {
            'name': self.number or None,
            'pay_now': 'pay_now',
            'voucher_type': 'purchase',
            'date': self.date,
            'journal_id': self.journal_id.id,
            'account_id': self.account_id.id,
            'move_id': self.move_id.id or None,
            'payslip_id': self.id,
        }
        ac_obj = ac_voucher.create(vals_ac)
        self.paid = True
        for l in self.line_ids:
            if l.salary_rule_id.code.capitalize() == 'Net':
                price = l.amount
                vals_ac_lin = {
                    'voucher_id':
                    ac_obj.id,
                    'name':
                    self.name,
                    'account_id':
                    l.salary_rule_id.account_credit.id or self.account_id.id,
                    'quantity':
                    1.0,
                    'price_unit':
                    price,
                    'company_id':
                    self.company_id.id,
                }
                ac_obj = ac_vc_lin.sudo().create(vals_ac_lin)

    #added by Sangita
    @api.multi
    def dummy_method_ytd(self):
        year_line = self.env['hr.payslip.year'].search([])
        year_line.unlink()
        for t in self:
            if t.employee_id and t.date_from:
                today = str(date.today())
                fiscal_year = self.env['account.fiscalyear'].search(
                    [('date_start', '<=', today), ('date_stop', '>=', today)],
                    limit=1)

                SQL = """
                    select hp.employee_id, hpl.salary_rule_id,sum(hpl.total) 
                    from hr_payslip_line as hpl 
                    inner join hr_payslip as hp
                    on hpl.slip_id = hp.id 
                    where hp.employee_id = %s and hp.state in ('done') and hp.date_from >= %s and date_to <= %s 
                    group by hpl.id ,hpl.salary_rule_id,hp.employee_id,hp.state

                """
                self.env.cr.execute(
                    SQL, (t.employee_id.id, str(
                        fiscal_year.date_start), str(t.date_to)))
                res = self.env.cr.fetchall()
                if res:
                    for line in res:
                        #                         print"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",line
                        self.env['hr.payslip.year'].create({
                            'salary_rule_id':
                            line[1],
                            'hr_payslip_id':
                            self.id,
                            'total':
                            line[2],
                        })
        return {
            'name':
            _('Leaves'),
            'view_type':
            'form',
            'view_mode':
            'tree,pivot,from',
            'res_model':
            'hr.payslip.year',
            'src_model':
            'hr.payslip',
            'type':
            'ir.actions.act_window',
            'context': {
                'search_default_employee_id': self.employee_id.id,
                'default_employee_id': self.employee_id.id,
                'group_by': 'salary_rule_id'
            },
            'search_view_id':
            self.env.ref('payslip_batch_extended.hr_payslip_year_tree').id
        }

    #added by sangita
    @api.multi
    def tod_calculate(self):
        for t in self:
            if t.employee_id and t.date_from:
                today = str(date.today())
                fiscal_year = self.env['account.fiscalyear'].search(
                    [('date_start', '<=', today), ('date_stop', '>=', today)],
                    limit=1)

                SQL = """
                    select hpl.salary_rule_id, hp.employee_id, hsr.name as name,sum(hpl.total) as tot 
                    from hr_payslip_line as hpl 
                    inner join hr_payslip as hp
                    on hpl.slip_id = hp.id
                    inner join hr_salary_rule hsr on hpl.salary_rule_id= hsr.id 
                    
                    where hp.employee_id = %s and hp.state in ('done') and hp.date_from >= %s and date_to <= %s
                    group by hpl.salary_rule_id,hp.employee_id,hsr.name order by hpl.salary_rule_id

                """
                self.env.cr.execute(
                    SQL, (t.employee_id.id, str(
                        fiscal_year.date_start), str(t.date_to)))
                res = self.env.cr.fetchall()
                print "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", res
                return res

    @api.multi
    def view_account_voucher(self):
        return {
            'name': _('Payment Order'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'account.voucher',
            'type': 'ir.actions.act_window',
            'domain': [('payslip_id', '=', self.id)],
        }

    #added by sangita
    @api.multi
    def hr_employee_holiday_request_leave_left(self):
        return {
            'name':
            _('Leaves'),
            'view_type':
            'form',
            'view_mode':
            'tree,form',
            'res_model':
            'hr.holidays',
            'src_model':
            'hr.employee',
            'type':
            'ir.actions.act_window',
            'domain': [('holiday_type', '=', 'employee'),
                       ('holiday_status_id.limit', '=', False),
                       ('state', '!=', 'refuse')],
            'context': {
                'search_default_employee_id': self.employee_id.id,
                'default_employee_id': self.employee_id.id,
                'search_default_group_type': 1,
                'search_default_year': 1
            },
            'search_view_id':
            self.env.ref('hr_holidays.view_hr_holidays_filter').id
        }

    #added by sangita
    @api.multi
    def compute_sheet(self):
        #         print"@@@@@@@@@@@@@@@@@@@@@@@@@@WWWWWWWWWWWWW"
        #         for contract in self.contract_id:
        #             self.account_id = contract.account_id.id
        #             print"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",s.account_id
        for s in self:
            for loan in s.loan_ids:
                if loan.date <= s.date_to:
                    loan.paid = True
            return super(HrPayslip, s).compute_sheet()

    @api.multi
    def refund_sheet(self):
        res = super(HrPayslip, self).refund_sheet()
        self.state = 'cancel'
        for s in self:
            for loan in s.loan_ids:
                if loan.date <= s.date_to:
                    loan.paid = False
        self.refund_id = res.ids
        return True

    @api.multi
    def refund_sheet(self):
        for payslip in self:
            copied_payslip = payslip.copy({
                'credit_note': True,
                'name': _('Refund: ') + payslip.name
            })
            copied_payslip.action_payslip_done()
            payslip.state = 'cancel'
            for loan in payslip.loan_ids:
                if loan.date <= payslip.date_to:
                    loan.paid = False
#         copied_payslip = self.copy({'credit_note': True, 'name': _('Refund: ') + s.name})
            payslip.refund_id = copied_payslip
        formview_ref = self.env.ref('hr_payroll.view_hr_payslip_form', False)
        treeview_ref = self.env.ref('hr_payroll.view_hr_payslip_tree', False)
        #         print"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<,",copied_payslip.ids
        return {
            'name': ("Refund Payslip"),
            'view_mode':
            'tree, form',
            'view_id':
            False,
            'view_type':
            'form',
            'res_model':
            'hr.payslip',
            'type':
            'ir.actions.do_nothing',
            'target':
            'current',
            'domain':
            "[('id', 'in', %s)]" % copied_payslip.ids,
            'views': [(treeview_ref and treeview_ref.id or False, 'tree'),
                      (formview_ref and formview_ref.id or False, 'form')],
            'context': {}
        }

    @api.model
    def create(self, vals):
        res = super(HrPayslip, self).create(vals)
        res.get_loan()
        return res

    @api.multi
    def action_payslip_done(self):
        res = super(HrPayslip, self).action_payslip_done()
        print "???????????????????????????????????????????"
        if self.state == 'done':
            lwp_id = self.env['hr.holidays'].search([('employee_id', '=',
                                                      self.employee_id.id)])
            for lwp in lwp_id:
                print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", lwp_id
                lwp.payslip_status = True
                lwp.payslip_id = self.id
        return res

    #Added by Sangita When in payslip select from date is jan and to date is feb the payslip name genereated by date to name
    @api.onchange('employee_id', 'date_from', 'date_to')
    def onchange_employee(self):

        if (not self.employee_id) or (not self.date_from) or (
                not self.date_to):
            return

        employee = self.employee_id
        date_from = self.date_from
        date_to = self.date_to

        ttyme = datetime.fromtimestamp(
            time.mktime(time.strptime(date_to, "%Y-%m-%d")))
        locale = self.env.context.get('lang', 'en_US')
        self.name = _('Salary Slip of %s for %s') % (
            employee.name,
            tools.ustr(
                babel.dates.format_date(
                    date=ttyme, format='MMMM-y', locale=locale)))
        self.company_id = employee.company_id

        if not self.env.context.get('contract') or not self.contract_id:
            contract_ids = self.get_contract(employee, date_from, date_to)
            if not contract_ids:
                return
            self.contract_id = self.env['hr.contract'].browse(contract_ids[0])

        if not self.contract_id.struct_id:
            return
        self.struct_id = self.contract_id.struct_id

        #computation of the salary input
        worked_days_line_ids = self.get_worked_day_lines(
            contract_ids, date_from, date_to)
        worked_days_lines = self.worked_days_line_ids.browse([])
        for r in worked_days_line_ids:
            worked_days_lines += worked_days_lines.new(r)
        self.worked_days_line_ids = worked_days_lines

        input_line_ids = self.get_inputs(contract_ids, date_from, date_to)
        input_lines = self.input_line_ids.browse([])
        for r in input_line_ids:
            input_lines += input_lines.new(r)
        self.input_line_ids = input_lines
        return
Exemple #28
0
class purchase_order(models.Model):
    _inherit = 'purchase.order'

    @api.model
    def create(self, vals):
        res = super(purchase_order, self).create(vals)
        discount_type_obj = self.env['discount.type']
        discount_type_percent = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_percent_id')
        discount_type_fixed = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_fixed_id')
        if vals.get('discount_value'):
            if vals.get('discount_type_id') == discount_type_percent:
                brw_type = discount_type_obj.browse(
                    discount_type_percent).discount_value
                if brw_type > 0.0:
                    if vals.get('discount_value', 0.00) > brw_type:
                        raise UserError(
                        _('You can not set Discount Value more then %s . \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type') % \
                        (brw_type , brw_type))
            elif vals.get('discount_type_id') == discount_type_fixed:
                brw_type = discount_type_obj.browse(
                    discount_type_fixed).discount_value
                if brw_type > 0.0:
                    if vals.get('discount_value', 0.00) > brw_type:
                        raise UserError(
                        _('You can not set Discount Value more then %s. \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type' ) % \
                        (brw_type ,brw_type ))
        return res

    def write(self, vals):
        res = super(purchase_order, self).write(vals)
        discount_type_percent = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_percent_id')
        discount_type_fixed = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_fixed_id')
        discount_type_obj = self.env['discount.type']
        if vals.get(
                'discount_type_id'
        ) == discount_type_percent or self.discount_type_id.id == discount_type_percent:
            brw_type = discount_type_obj.browse(
                discount_type_percent).discount_value
            if brw_type > 0.0:
                if vals.get('discount_value', 0.00) > brw_type:
                    raise UserError(
                    _('You can not set Discount Value more then %s . \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type') % \
                    (brw_type , brw_type))
        if vals.get(
                'discount_type_id'
        ) == discount_type_fixed or self.discount_type_id.id == discount_type_fixed:
            brw_type = discount_type_obj.browse(
                discount_type_fixed).discount_value
            if brw_type > 0.0:
                if vals.get('discount_value', 0.00) > brw_type:
                    raise UserError(
                    _('You can not set Discount Value more then %s. \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type' ) % \
                    (brw_type ,brw_type ))
        if vals.get('discount_value'):
            if self.discount_type_id.id == discount_type_percent:
                brw_type = discount_type_obj.browse(
                    discount_type_percent).discount_value
                if brw_type > 0.0:
                    if vals.get('discount_value', 0.00) > brw_type:
                        raise UserError(
                        _('You can not set Discount Value more then %s. \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type') % \
                        (brw_type , brw_type))
            elif self.discount_type_id.id == discount_type_fixed:
                brw_type = discount_type_obj.browse(
                    discount_type_fixed).discount_value
                if brw_type > 0.0:
                    if vals.get('discount_value', 0.00) > brw_type:
                        raise UserError(
                        _('You can not set Discount Value more then %s. \n Maximum Discount value is %s \n Set maximum value Purchase-> Configuration-> Discount Type' ) % \
                        (brw_type ,brw_type ))
        return res

    @api.onchange('apply_discount')
    def onchange_apply_discount(self):
        if self.apply_discount:
            account_search = self.env['account.account'].search([
                ('discount_account', '=', True),
                ('user_type_id.internal_group', '=', 'income')
            ])
            if account_search:
                self.discount_account = account_search[0].id

    @api.depends('order_line.price_total', 'discount_value',
                 'discount_type_id', 'apply_discount')
    def _amount_all(self):
        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
            if not order.apply_discount:
                order.amount_after_discount = 0.0
            if order.amount_after_discount:
                order.update({
                    'amount_untaxed':
                    order.currency_id.round(amount_untaxed),
                    'amount_tax':
                    order.currency_id.round(amount_tax),
                    'amount_total':
                    order.amount_after_discount +
                    order.currency_id.round(amount_tax),
                })
            else:
                order.update({
                    'amount_untaxed':
                    order.currency_id.round(amount_untaxed),
                    'amount_tax':
                    order.currency_id.round(amount_tax),
                    'amount_total':
                    amount_untaxed + amount_tax,
                })

    @api.depends('discount_value', 'order_line.price_total',
                 'discount_type_id')
    def _compute_amount_after_discount(self):
        discount = 0.0
        amount_untaxed = 0.0
        discount_type_percent = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_percent_id')

        discount_type_fixed = self.env['ir.model.data'].xmlid_to_res_id(
            'bi_sale_purchase_invoice_discount.discount_type_fixed_id')
        for self_obj in self:
            for line in self_obj.order_line:
                amount_untaxed += line.price_subtotal
            if self_obj.discount_type_id.id == discount_type_fixed:
                discount = amount_untaxed - self_obj.discount_value
                self_obj.amount_after_discount = discount
            elif self_obj.discount_type_id.id == discount_type_percent:
                discount_percent = amount_untaxed * (
                    (self_obj.discount_value or 0.0) / 100.0)
                discount = amount_untaxed - discount_percent
                self_obj.amount_after_discount = discount
            else:
                self_obj.amount_after_discount = discount

    apply_discount = fields.Boolean('Apply Discount')
    discount_type_id = fields.Many2one('discount.type', 'Discount Type')
    discount_value = fields.Float('Purchase Discount')
    discount_account = fields.Many2one('account.account', 'Discount Account')
    amount_after_discount = fields.Monetary(
        'Amount After Discount',
        store=True,
        readonly=True,
        compute='_compute_amount_after_discount')
Exemple #29
0
class AccountPayment(models.Model):
    _inherit = "account.payment"

    payment_group_id = fields.Many2one(
        'account.payment.group',
        'Payment Group',
        ondelete='cascade',
        readonly=True,
    )
    # we add this field so company can be send in context when adding payments
    # before payment group is saved
    payment_group_company_id = fields.Many2one(
        related='payment_group_id.company_id',
        readonly=True,
    )
    # we make a copy without transfer option, we try with related but it
    # does not works
    payment_type_copy = fields.Selection(selection=[('outbound', 'Send Money'),
                                                    ('inbound',
                                                     'Receive Money')],
                                         compute='_compute_payment_type_copy',
                                         inverse='_inverse_payment_type_copy',
                                         string='Payment Type')
    signed_amount = fields.Monetary(
        string='Payment Amount',
        compute='_compute_signed_amount',
    )
    signed_amount_company_currency = fields.Monetary(
        string='Payment Amount on Company Currency',
        compute='_compute_signed_amount',
        currency_field='company_currency_id',
    )
    amount_company_currency = fields.Monetary(
        string='Payment Amount on Company Currency',
        compute='_compute_amount_company_currency',
        inverse='_inverse_amount_company_currency',
        currency_field='company_currency_id',
    )
    other_currency = fields.Boolean(compute='_compute_other_currency', )
    force_amount_company_currency = fields.Monetary(
        string='Payment Amount on Company Currency',
        currency_field='company_currency_id',
        copy=False,
    )
    exchange_rate = fields.Float(
        string='Exchange Rate',
        compute='_compute_exchange_rate',
        # readonly=False,
        # inverse='_inverse_exchange_rate',
        digits=(16, 4),
    )
    company_currency_id = fields.Many2one(
        related='company_id.currency_id',
        readonly=True,
    )

    @api.multi
    @api.depends('amount', 'payment_type', 'partner_type',
                 'amount_company_currency')
    def _compute_signed_amount(self):
        for rec in self:
            sign = 1.0
            if ((rec.partner_type == 'supplier'
                 and rec.payment_type == 'inbound')
                    or (rec.partner_type == 'customer'
                        and rec.payment_type == 'outbound')):
                sign = -1.0
            rec.signed_amount = rec.amount and rec.amount * sign
            rec.signed_amount_company_currency = (
                rec.amount_company_currency
                and rec.amount_company_currency * sign)

    @api.multi
    @api.depends('currency_id', 'company_currency_id')
    def _compute_other_currency(self):
        for rec in self:
            if rec.company_currency_id and rec.currency_id and \
                    rec.company_currency_id != rec.currency_id:
                rec.other_currency = True

    @api.multi
    @api.depends('amount', 'other_currency', 'amount_company_currency')
    def _compute_exchange_rate(self):
        for rec in self.filtered('other_currency'):
            rec.exchange_rate = rec.amount and (rec.amount_company_currency /
                                                rec.amount) or 0.0

    @api.multi
    # this onchange is necesary because odoo, sometimes, re-compute
    # and overwrites amount_company_currency. That happends due to an issue
    # with rounding of amount field (amount field is not change but due to
    # rouding odoo believes amount has changed)
    @api.onchange('amount_company_currency')
    def _inverse_amount_company_currency(self):
        _logger.info('Running inverse amount company currency')
        for rec in self:
            if rec.other_currency and rec.amount_company_currency != \
                    rec.currency_id.with_context(
                        date=rec.payment_date).compute(
                        rec.amount, rec.company_id.currency_id):
                force_amount_company_currency = rec.amount_company_currency
            else:
                force_amount_company_currency = False
            rec.force_amount_company_currency = force_amount_company_currency

    @api.multi
    @api.depends('amount', 'other_currency', 'force_amount_company_currency')
    def _compute_amount_company_currency(self):
        """
        * Si las monedas son iguales devuelve 1
        * si no, si hay force_amount_company_currency, devuelve ese valor
        * sino, devuelve el amount convertido a la moneda de la cia
        """
        _logger.info('Computing amount company currency')
        for rec in self:
            if not rec.other_currency:
                amount_company_currency = rec.amount
            elif rec.force_amount_company_currency:
                amount_company_currency = rec.force_amount_company_currency
            else:
                amount_company_currency = rec.currency_id.with_context(
                    date=rec.payment_date).compute(rec.amount,
                                                   rec.company_id.currency_id)
            rec.amount_company_currency = amount_company_currency

    @api.multi
    @api.onchange('payment_type_copy')
    def _inverse_payment_type_copy(self):
        for rec in self:
            # if false, then it is a transfer
            rec.payment_type = (rec.payment_type_copy and rec.payment_type_copy
                                or 'transfer')

    @api.multi
    @api.depends('payment_type')
    def _compute_payment_type_copy(self):
        for rec in self:
            if rec.payment_type == 'transfer':
                continue
            rec.payment_type_copy = rec.payment_type

    @api.multi
    def get_journals_domain(self):
        domain = super(AccountPayment, self).get_journals_domain()
        if self.payment_group_company_id:
            domain.append(
                ('company_id', '=', self.payment_group_company_id.id))
        return domain

    @api.onchange('payment_type')
    def _onchange_payment_type(self):
        """
        we disable change of partner_type if we came from a payment_group
        but we still reset the journal
        """
        if not self._context.get('payment_group'):
            return super(AccountPayment, self)._onchange_payment_type()
        self.journal_id = False

    @api.multi
    @api.constrains('payment_group_id', 'payment_type')
    def check_payment_group(self):
        # odoo tests don't create payments with payment gorups
        if self.env.registry.in_test_mode():
            return True
        for rec in self:
            if rec.partner_type and not rec.payment_group_id:
                raise ValidationError(
                    _('Payments with partners must be created from '
                      'payments groups'))
            # transfers or payments from bank reconciliation without partners
            elif not rec.partner_type and rec.payment_group_id:
                raise ValidationError(
                    _("Payments without partners (usually transfers) cant't "
                      "have a related payment group"))

    @api.model
    def create(self, vals):
        # when payments are created from bank reconciliation create the
        # payment group before creating payment to aboid raising error
        if vals.get('state') == 'reconciled' and vals.get('partner_type'):
            company_id = self.env['account.journal'].browse(
                vals.get('journal_id')).company_id.id
            payment_group = self.env['account.payment.group'].create({
                'company_id':
                company_id,
                'partner_type':
                vals.get('partner_type'),
                'partner_id':
                vals.get('partner_id'),
                'payment_date':
                vals.get('payment_date'),
                'communication':
                vals.get('communication'),
                'state':
                'posted',
            })
            vals['payment_group_id'] = payment_group.id
        payment = super(AccountPayment, self).create(vals)
        return payment

    @api.multi
    @api.depends('invoice_ids', 'payment_type', 'partner_type', 'partner_id')
    def _compute_destination_account_id(self):
        """
        If we are paying a payment gorup with paylines, we use account
        of lines that are going to be paid
        """
        for rec in self:
            to_pay_account = rec.payment_group_id.to_pay_move_line_ids.mapped(
                'account_id')
            if len(to_pay_account) > 1:
                raise ValidationError(
                    _('To Pay Lines must be of the same account!'))
            elif len(to_pay_account) == 1:
                rec.destination_account_id = to_pay_account[0]
            else:
                super(AccountPayment, rec)._compute_destination_account_id()

    @api.multi
    def show_details(self):
        """
        Metodo para mostrar form editable de payment, principalmente para ser
        usado cuando hacemos ajustes y el payment group esta confirmado pero
        queremos editar una linea
        """
        return {
            'name': _('Payment Lines'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'account.payment',
            'target': 'new',
            'res_id': self.id,
            'context': self._context,
        }

    def _get_shared_move_line_vals(self,
                                   debit,
                                   credit,
                                   amount_currency,
                                   move_id,
                                   invoice_id=False):
        """
        Si se esta forzando importe en moneda de cia, usamos este importe
        para debito/credito
        """
        res = super(AccountPayment,
                    self)._get_shared_move_line_vals(debit,
                                                     credit,
                                                     amount_currency,
                                                     move_id,
                                                     invoice_id=invoice_id)
        if self.force_amount_company_currency:
            if res.get('debit', False):
                res['debit'] = self.force_amount_company_currency
            if res.get('credit', False):
                res['credit'] = self.force_amount_company_currency
        return res

    def _get_move_vals(self, journal=None):
        """If we have a communication on payment group append it before
        payment communication
        """
        vals = super(AccountPayment, self)._get_move_vals(journal=journal)
        if self.payment_group_id.communication:
            vals['ref'] = "%s%s" % (self.payment_group_id.communication,
                                    self.communication
                                    and ": %s" % self.communication or "")
        return vals
Exemple #30
0
class InventoryLine(models.Model):
    _name = "stock.inventory.line"
    _description = "Inventory Line"
    _order = "product_name ,inventory_id, location_name, product_code, prodlot_name"

    inventory_id = fields.Many2one(
        'stock.inventory', 'Inventory',
        index=True, ondelete='cascade')
    partner_id = fields.Many2one('res.partner', 'Owner')
    product_id = fields.Many2one(
        'product.product', 'Product',
        index=True, required=True)
    product_name = fields.Char(
        'Product Name', related='product_id.name', store=True)
    product_code = fields.Char(
        'Product Code', related='product_id.default_code', store=True)
    product_uom_id = fields.Many2one(
        'product.uom', 'Product Unit of Measure',
        required=True,
        default=lambda self: self.env.ref('product.product_uom_unit', raise_if_not_found=True))
    product_qty = fields.Float(
        'Checked Quantity',
        digits=dp.get_precision('Product Unit of Measure'), default=0)
    location_id = fields.Many2one(
        'stock.location', 'Location',
        index=True, required=True)
    # TDE FIXME: necessary ? only in order -> replace by location_id
    location_name = fields.Char(
        'Location Name', related='location_id.complete_name', store=True)
    package_id = fields.Many2one(
        'stock.quant.package', 'Pack', index=True)
    prod_lot_id = fields.Many2one(
        'stock.production.lot', 'Lot/Serial Number',
        domain="[('product_id','=',product_id)]")
    # TDE FIXME: necessary ? -> replace by location_id
    prodlot_name = fields.Char(
        'Serial Number Name',
        related='prod_lot_id.name', store=True)
    company_id = fields.Many2one(
        'res.company', 'Company', related='inventory_id.company_id',
        index=True, readonly=True, store=True)
    # TDE FIXME: necessary ? -> replace by location_id
    state = fields.Selection(
        'Status',  related='inventory_id.state', readonly=True)
    theoretical_qty = fields.Float(
        'Theoretical Quantity', compute='_compute_theoretical_qty',
        digits=dp.get_precision('Product Unit of Measure'), readonly=True, store=True)

    @api.one
    @api.depends('location_id', 'product_id', 'package_id', 'product_uom_id', 'company_id', 'prod_lot_id', 'partner_id')
    def _compute_theoretical_qty(self):
        if not self.product_id:
            self.theoretical_qty = 0
            return
        theoretical_qty = sum([x.qty for x in self._get_quants()])
        if theoretical_qty and self.product_uom_id and self.product_id.uom_id != self.product_uom_id:
            theoretical_qty = self.product_id.uom_id._compute_quantity(theoretical_qty, self.product_uom_id)
        self.theoretical_qty = theoretical_qty

    @api.onchange('product_id')
    def onchange_product(self):
        res = {}
        # If no UoM or incorrect UoM put default one from product
        if self.product_id:
            self.product_uom_id = self.product_id.uom_id
            res['domain'] = {'product_uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
        return res

    @api.onchange('product_id', 'location_id', 'product_uom_id', 'prod_lot_id', 'partner_id', 'package_id')
    def onchange_quantity_context(self):
        if self.product_id and self.location_id and self.product_id.uom_id.category_id == self.product_uom_id.category_id:  # TDE FIXME: last part added because crash
            self._compute_theoretical_qty()
            self.product_qty = self.theoretical_qty

    @api.model
    def create(self, values):
        if 'product_id' in values and 'product_uom_id' not in values:
            values['product_uom_id'] = self.env['product.product'].browse(values['product_id']).uom_id.id
        existings = self.search([
            ('product_id', '=', values.get('product_id')),
            ('inventory_id.state', '=', 'confirm'),
            ('location_id', '=', values.get('location_id')),
            ('partner_id', '=', values.get('partner_id')),
            ('package_id', '=', values.get('package_id')),
            ('prod_lot_id', '=', values.get('prod_lot_id'))])
        res = super(InventoryLine, self).create(values)
        if existings:
            raise UserError(_("You cannot have two inventory adjustements in state 'in Progess' with the same product"
                              "(%s), same location(%s), same package, same owner and same lot. Please first validate"
                              "the first inventory adjustement with this product before creating another one.") % (res.product_id.name, res.location_id.name))
        return res

    def _get_quants(self):
        return self.env['stock.quant'].search([
            ('company_id', '=', self.company_id.id),
            ('location_id', '=', self.location_id.id),
            ('lot_id', '=', self.prod_lot_id.id),
            ('product_id', '=', self.product_id.id),
            ('owner_id', '=', self.partner_id.id),
            ('package_id', '=', self.package_id.id)])

    def _get_move_values(self, qty, location_id, location_dest_id):
        self.ensure_one()
        return {
            'name': _('INV:') + (self.inventory_id.name or ''),
            'product_id': self.product_id.id,
            'product_uom': self.product_uom_id.id,
            'product_uom_qty': qty,
            'date': self.inventory_id.date,
            'company_id': self.inventory_id.company_id.id,
            'inventory_id': self.inventory_id.id,
            'state': 'confirmed',
            'restrict_lot_id': self.prod_lot_id.id,
            'restrict_partner_id': self.partner_id.id,
            'location_id': location_id,
            'location_dest_id': location_dest_id,
        }

    def _fixup_negative_quants(self):
        """ This will handle the irreconciable quants created by a force availability followed by a
        return. When generating the moves of an inventory line, we look for quants of this line's
        product created to compensate a force availability. If there are some and if the quant
        which it is propagated from is still in the same location, we move it to the inventory
        adjustment location before getting it back. Getting the quantity from the inventory
        location will allow the negative quant to be compensated.
        """
        self.ensure_one()
        for quant in self._get_quants().filtered(lambda q: q.propagated_from_id.location_id.id == self.location_id.id):
            # send the quantity to the inventory adjustment location
            move_out_vals = self._get_move_values(quant.qty, self.location_id.id, self.product_id.property_stock_inventory.id)
            move_out = self.env['stock.move'].create(move_out_vals)
            self.env['stock.quant'].quants_reserve([(quant, quant.qty)], move_out)
            move_out.action_done()

            # get back the quantity from the inventory adjustment location
            move_in_vals = self._get_move_values(quant.qty, self.product_id.property_stock_inventory.id, self.location_id.id)
            move_in = self.env['stock.move'].create(move_in_vals)
            move_in.action_done()

    def _generate_moves(self):
        moves = self.env['stock.move']
        Quant = self.env['stock.quant']
        for line in self:
            line._fixup_negative_quants()

            if float_utils.float_compare(line.theoretical_qty, line.product_qty, precision_rounding=line.product_id.uom_id.rounding) == 0:
                continue
            diff = line.theoretical_qty - line.product_qty
            if diff < 0:  # found more than expected
                vals = self._get_move_values(abs(diff), line.product_id.property_stock_inventory.id, line.location_id.id)
            else:
                vals = self._get_move_values(abs(diff), line.location_id.id, line.product_id.property_stock_inventory.id)
            move = moves.create(vals)

            if diff > 0:
                domain = [('qty', '>', 0.0), ('package_id', '=', line.package_id.id), ('lot_id', '=', line.prod_lot_id.id), ('location_id', '=', line.location_id.id)]
                preferred_domain_list = [[('reservation_id', '=', False)], [('reservation_id.inventory_id', '!=', line.inventory_id.id)]]
                quants = Quant.quants_get_preferred_domain(move.product_qty, move, domain=domain, preferred_domain_list=preferred_domain_list)
                Quant.quants_reserve(quants, move)
            elif line.package_id:
                move.action_done()
                move.quant_ids.write({'package_id': line.package_id.id})
                quants = Quant.search([('qty', '<', 0.0), ('product_id', '=', move.product_id.id),
                                       ('location_id', '=', move.location_dest_id.id), ('package_id', '!=', False)], limit=1)
                if quants:
                    for quant in move.quant_ids:
                        if quant.location_id.id == move.location_dest_id.id:  #To avoid we take a quant that was reconcile already
                            quant._quant_reconcile_negative(move)
        return moves