class fido_bagger_line(models.Model):
    _name = "fido.bagger.line"
    bagger_id = fields.Many2one('fido.bagger', string='Fido Reference')
    fido_date = fields.Date(default=fields.Date.today(), required=True)
    x_quantity = fields.Integer(string="No of Bags", required=True)
Exemple #2
0
class AccountAsset(ChartFieldAction, models.Model):
    _name = 'account.asset'
    _inherit = ['account.asset', 'mail.thread']

    name = fields.Char(
        default='/',
        readonly=False,
        states={},  # Always editable
    )
    parent_id = fields.Many2one(
        readonly=False,
        states={},  # Procurement team want it to always editable.
    )
    type = fields.Selection(
        # Need this way of doing default, because default_type in context will
        # cause problem compute depreciation table, it set line type wrongly
        default=lambda self: self._context.get('type') or 'normal', )
    profile_type = fields.Selection(
        [('normal', 'Normal'), ('normal_nod', 'Normal (No-Depre)'),
         ('ait', 'AIT'), ('auc', 'AUC'), ('lva', 'Low-Value'), ('atm', 'ATM')],
        related='profile_id.profile_type',
        string='Asset Profile Type',
        store=True,
        readonly=True,
    )
    status = fields.Many2one(
        'account.asset.status',
        string='Asset Status',
        default=lambda self: self.env.ref('pabi_asset_management.'
                                          'asset_status_cancel'),
        domain="[('map_state', '=', state)]",
        required=False,
        index=True,
        help="Status vs State\n"
        "Draft → ยกเลิก\n"
        "Running → ใช้งานปกติ, ส่งมอบ, โอนเป็นครุภัณฑ์, ชำรุด, รอจำหน่าย\n"
        "Removed → จำหน่าย, สูญหาย\n"
        "Close → หมดอายุการใช้งาน")
    status_code = fields.Char(
        string='Status Code',
        related='status.code',
        readonly=True,
        store=True,
    )
    deliver_to = fields.Char(
        string='Deliver to',
        help="If status is chagned to 'delivery', this field is required",
    )
    deliver_date = fields.Date(
        string='Delivery date',
        help="If status is chagned to 'delivery', this field is required",
    )
    code = fields.Char(
        string='Code',  # Rename
        default='/',
    )
    code2 = fields.Char(
        string='Code (legacy)',
        help="Code in Legacy System",
    )
    product_id = fields.Many2one(
        'product.product',
        string='Asset Type',
        domain=[('asset_profile_id', '!=', False)],
        readonly=True,
        states={'draft': [('readonly', False)]},
        help="This asset is created from this product class",
    )
    move_id = fields.Many2one(
        'stock.move',
        string='Move',
        readonly=True,
    )
    picking_id = fields.Many2one(
        'stock.picking',
        string='Picking',
        related='move_id.picking_id',
        store=True,
        readonly=True,
    )
    adjust_id = fields.Many2one(
        'account.asset.adjust',
        string='Adjustment',
        readonly=True,
        copy=False,
        help="For asset that is created from the asset type adjustment",
    )
    date_picking = fields.Datetime(
        string='Picking Date',
        related='move_id.picking_id.date_done',
        readonly=True,
    )
    purchase_id = fields.Many2one(
        'purchase.order',
        string='Purchase Order',
        related='move_id.purchase_line_id.order_id',
        store=True,
        readonly=True,
    )
    uom_id = fields.Many2one(
        'product.uom',
        string='Unit of Measure',
        related='move_id.product_uom',
        store=True,
        readonly=True,
    )
    no_depreciation = fields.Boolean(
        string='No Depreciation',
        related='profile_id.no_depreciation',
        readonly=True,
    )
    # Additional Info
    asset_purchase_method_id = fields.Many2one(
        'asset.purchase.method',
        string='Purchase Method',
    )
    purchase_request_id = fields.Many2one(
        'purchase.request',
        string='Purchase Request',
        related='move_id.purchase_line_id.quo_line_id.requisition_line_id.'
        'purchase_request_lines.request_id',
        readonly=True,
        help="PR of this asset",
    )
    pr_requester_id = fields.Many2one(
        'res.users',
        string='PR Requester',
        related='purchase_request_id.requested_by',
        readonly=True,
        help="PR Requester of this asset",
    )
    date_request = fields.Date(
        string='PR Approved Date',
        related='move_id.purchase_line_id.quo_line_id.requisition_line_id.'
        'purchase_request_lines.request_id.date_approve',
        readonly=True,
        help="PR's Approved Date",
    )
    doc_request_id = fields.Many2one(
        'account.asset.request',
        string='Asset Request',
        readonly=True,
    )
    responsible_user_id = fields.Many2one(
        'res.users',
        string='Responsible Person',
        readonly=True,
        states={'draft': [('readonly', False)]},
    )
    owner_project_id = fields.Many2one(
        'res.project',
        string='Project',
        readonly=True,
        help="Owner project of the budget structure",
    )
    owner_section_id = fields.Many2one(
        'res.section',
        string='Section',
        readonly=True,
        help="Owner section of the budget structure",
    )
    purchase_value = fields.Float(
        default=0.0,  # to avoid false
    )
    requester_id = fields.Many2one(
        'res.users',
        string='Requester',
        readonly=True,
        states={'draft': [('readonly', False)]},
    )
    building_id = fields.Many2one(
        'res.building',
        string='Building',
        readonly=True,
        states={'draft': [('readonly', False)]},
        ondelete='restrict',
    )
    floor_id = fields.Many2one(
        'res.floor',
        string='Floor',
        readonly=True,
        states={'draft': [('readonly', False)]},
        ondelete='restrict',
    )
    room_id = fields.Many2one(
        'res.room',
        string='Room',
        readonly=True,
        states={'draft': [('readonly', False)]},
    )
    serial_number = fields.Char(
        string='Serial Number',
        readonly=False,
    )
    warranty_start_date = fields.Date(
        string='Warranty Start Date',
        default=lambda self: fields.Date.context_today(self),
        track_visibility='onchange',
        readonly=False,
    )
    warranty_expire_date = fields.Date(
        string='Warranty Expire Date',
        default=lambda self: fields.Date.context_today(self),
        track_visibility='onchange',
        readonly=False,
    )
    # Transfer Asset
    target_asset_ids = fields.Many2many(
        'account.asset',
        'account_asset_source_target_rel',
        'source_asset_id',
        'target_asset_id',
        string='To Asset(s)',
        domain=['|', ('active', '=', True), ('active', '=', False)],
        help="In case of transfer, this field show asset created by this one",
        readonly=True,
    )
    target_asset_count = fields.Integer(
        string='Source Asset Count',
        compute='_compute_asset_count',
    )
    source_asset_ids = fields.Many2many(
        'account.asset',
        'account_asset_source_target_rel',
        'target_asset_id',
        'source_asset_id',
        string='From Asset(s)',
        domain=['|', ('active', '=', True), ('active', '=', False)],
        help="List of source asset that has been transfer to this one",
    )
    source_asset_count = fields.Integer(
        string='Source Asset Count',
        compute='_compute_asset_count',
    )
    image = fields.Binary(string='Image', )
    repair_note_ids = fields.One2many(
        'asset.repair.note',
        'asset_id',
        string='Repair Notes',
    )
    depreciation_summary_ids = fields.One2many(
        'account.asset.depreciation.summary',
        'asset_id',
        string='Depreciation Summary',
        readonly=True,
    )
    parent_type = fields.Selection(
        [
            ('ait', 'AIT'),
            ('auc', 'AUC'),
            ('atm', 'ATM'),
        ],
        string='Parent Type',
        default='atm',
    )
    installment = fields.Integer(
        string='Installment',
        readonly=True,
        help="Installment, if related to PO's invoice plan",
    )
    num_installment = fields.Integer(
        string='Number of Installment',
        readonly=True,
        help="Total Installment, if related to PO's invoice plan",
    )
    installment_str = fields.Char(
        string='Installment',
        compute='_compute_installment_str',
        help="Nicely format installment vs number of installment",
    )
    total_child_value = fields.Float(
        string='Total Value',
        compute='_compute_total_child_value',
        help="Sum of this parent's child purchase values",
    )
    child_asset_count = fields.Integer(
        string='Child Asset Count',
        compute='_compute_asset_count',
    )
    # Special field that search PO through adjustmnet and po
    all_purchase = fields.Char(
        string='All Purchase Orders',
        help="Search POs from purchase_id and "
        "adjust_id.invoice_id.expense_id.ship_purchase_id",
    )
    _sql_constraints = [('code_uniq', 'unique(code)',
                         'Asset Code must be unique!')]

    # Building / Floor / Room
    @api.multi
    @api.constrains('building_id', 'floor_id', 'room_id')
    def _check_building(self):
        for rec in self:
            self.env['res.building']._check_room_location(
                rec.building_id, rec.floor_id, rec.room_id)

    @api.onchange('building_id')
    def _onchange_building_id(self):
        self.floor_id = False
        self.room_id = False

    @api.onchange('floor_id')
    def _onchange_floor_id(self):
        self.room_id = False

    @api.multi
    def _compute_total_child_value(self):
        for rec in self:
            rec.total_child_value = sum(rec.child_ids.mapped('purchase_value'))

    @api.multi
    @api.depends('installment')
    def _compute_installment_str(self):
        for rec in self:
            if rec.installment:
                rec.installment_str = '%s/%s' % (rec.installment,
                                                 rec.num_installment)

    @api.multi
    def validate_asset_to_request(self):
        invalid_assets = len(
            self.filtered(lambda l: l.doc_request_id or l.type != 'normal' or l
                          .state != 'open'))
        if invalid_assets > 0:
            raise ValidationError(
                _('Please select only running assets '
                  'that has not been requested yet!'))
        return True

    @api.multi
    def validate_asset_to_removal(self):
        invalid_assets = len(
            self.filtered(lambda l: l.type != 'normal' or l.state != 'open'))
        if invalid_assets > 0:
            raise ValidationError(_('Please select only running assets!'))
        return True

    @api.multi
    def action_undeliver_assets(self):
        """ This function is used for parent asset only """
        status_normal = self.env.ref('pabi_asset_management.'
                                     'asset_status_normal')
        for rec in self:
            rec.child_ids.write({
                'status': status_normal.id,
                'deliver_to': False,
                'deliver_date': False
            })
            rec.state = 'draft'

    @api.multi
    def write(self, vals):
        Status = self.env['account.asset.status']
        # Status follow state
        if 'state' in vals and vals.get('state', False):
            if vals.get('state') == 'close':
                vals['status'] = Status.search([('code', '=', 'expire')]).id
            if vals.get('state') == 'open':
                vals['status'] = Status.search([('code', '=', 'normal')]).id
            if vals.get('state') == 'draft':
                vals['status'] = Status.search([('code', '=', 'cancel')]).id
            # For removed, the state will be set in remove wizard
        # Validate status change must be within status map
        elif 'status' in vals and vals.get('status', False):
            status = Status.browse(vals.get('status'))
            for asset in self:
                if status.map_state != asset.state:
                    raise ValidationError(_('Invalid change of asset status'))
        res = super(AccountAsset, self).write(vals)
        # # Following code repeat the compute depre, but w/o it, value is zero
        # for asset in self:
        #     if asset.profile_id.open_asset and \
        #             self._context.get('create_asset_from_move_line'):
        #         asset.compute_depreciation_board()
        # # --
        return res

    @api.multi
    def open_source_asset(self):
        self.ensure_one()
        action = self.env.ref('account_asset_management.account_asset_action')
        result = action.read()[0]
        assets = self.with_context(active_test=False).\
            search([('id', 'in', self.source_asset_ids.ids)])
        dom = [('id', 'in', assets.ids)]
        result.update({'domain': dom, 'context': {'active_test': False}})
        return result

    @api.multi
    def open_target_asset(self):
        self.ensure_one()
        action = self.env.ref('account_asset_management.account_asset_action')
        result = action.read()[0]
        assets = self.with_context(active_test=False).\
            search([('id', 'in', self.target_asset_ids.ids)])
        dom = [('id', 'in', assets.ids)]
        result.update({'domain': dom, 'context': {'active_test': False}})
        return result

    @api.multi
    def open_depreciation_lines(self):
        self.ensure_one()
        action = self.env.ref('pabi_asset_management.'
                              'action_account_asset_line')
        result = action.read()[0]
        dom = [('asset_id', '=', self.id)]
        result.update({'domain': dom})
        return result

    @api.multi
    def open_child_asset(self):
        self.ensure_one()
        action = self.env.ref('account_asset_management.account_asset_action')
        result = action.read()[0]
        assets = self.with_context(active_test=False).\
            search([('id', 'in', self.child_ids.ids)])
        dom = [('id', 'in', assets.ids)]
        result.update({'domain': dom, 'context': {'active_test': False}})
        return result

    @api.multi
    def _compute_asset_count(self):
        # self = self.with_context(active_test=False)
        for asset in self:
            # _ids = self.with_context(active_test=False).\
            #     search([('target_asset_ids', 'in', [asset.id])])._ids
            asset.source_asset_count = \
                len(asset.with_context(active_test=False).source_asset_ids)
            asset.target_asset_count = \
                len(asset.with_context(active_test=False).target_asset_ids)
            asset.child_asset_count = \
                len(asset.with_context(active_test=False).child_ids)

    @api.model
    def create(self, vals):
        # Case Parent Assets, AIT, AUC, ATM
        type = vals.get('type', False)
        ptype = vals.get('parent_type', False)
        if ptype and type == 'view':
            sequence_code = 'parent.asset.%s' % (ptype)
            vals['code'] = self.env['ir.sequence'].next_by_code(sequence_code)
        # Normal Case
        product_id = vals.get('product_id', False)
        if product_id:
            product = self.env['product.product'].browse(product_id)
            sequence = product.sequence_id
            if not sequence:
                raise ValidationError(
                    _('No asset sequence setup for selected product!'))
            vals['code'] = self.env['ir.sequence'].next_by_id(sequence.id)

        # Set Salvage Value from Category
        profile_id = vals.get('profile_id', False)
        if profile_id:
            profile = self.env['account.asset.profile'].browse(profile_id)
            if profile and not profile.no_depreciation:
                vals['salvage_value'] = profile.salvage_value
        # --
        asset = super(AccountAsset, self).create(vals)
        # Moved to before create
        # if asset.profile_id and not asset.profile_id.no_depreciation:
        #     # This will also trigger new calc of depre base
        #     asset._write({'salvage_value': asset.profile_id.salvage_value})
        asset.update_related_dimension(vals)
        return asset

    @api.multi
    def name_get(self):
        res = []
        for record in self:
            if record.code and record.code != '/':
                name = "[%s] %s" % (record.code, record.name)
            else:
                name = record.name
            res.append((record.id, name))
        return res

    @api.multi
    def compute_depreciation_board(self):
        assets = self.filtered(lambda l: not l.no_depreciation)
        return super(AccountAsset, assets).compute_depreciation_board()

    # @api.multi
    # def onchange_profile_id(self, profile_id):
    #     res = super(AccountAsset, self).onchange_profile_id(profile_id)
    #     asset_profile = self.env['account.asset.profile'].browse(profile_id)
    #     if asset_profile and not asset_profile.no_depreciation:
    #         res['value']['salvage_value'] = asset_profile.salvage_value
    #     return res

    @api.onchange('profile_id')
    def _onchange_profile_id(self):
        super(AccountAsset, self)._onchange_profile_id()
        if self.profile_id and not self.profile_id.no_depreciation:
            self.salvage_value = self.profile_id.salvage_value

    # Method used in change owner and transfer

    @api.model
    def _prepare_asset_reverse_moves(self, assets):
        AccountMoveLine = self.env['account.move.line']
        default = {
            'move_id': False,
            'parent_asset_id': False,
            'asset_profile_id': False,
            'product_id': False,
            'partner_id': False,
            'stock_move_id': False,
        }
        asset_move_lines_dict = []
        depre_move_lines_dict = []
        for asset in assets:
            account_asset_id = asset.profile_id.account_asset_id.id
            account_depre_id = asset.profile_id.account_depreciation_id.id
            # Getting the origin move_line (1 asset value and 1 depreciation)
            # Asset
            asset_lines = AccountMoveLine.search(
                [  # Should have 1 line
                    ('asset_id', '=', asset.id),
                    ('account_id', '=', account_asset_id),
                    # Same Owner
                    ('project_id', '=', asset.owner_project_id.id),
                    ('section_id', '=', asset.owner_section_id.id),
                ],
                order='id asc')
            if asset_lines:
                asset_line_dict = asset_lines[0].copy_data(default)[0]
                debit = sum(asset_lines.mapped('debit'))
                credit = sum(asset_lines.mapped('credit'))
                if debit > credit:
                    asset_line_dict['credit'] = debit - credit
                    asset_line_dict['debit'] = False
                else:
                    asset_line_dict['credit'] = False
                    asset_line_dict['debit'] = credit - debit
                asset_move_lines_dict.append(asset_line_dict)
            # Depre
            depre_lines = AccountMoveLine.search(
                [
                    ('asset_id', '=', asset.id),
                    ('account_id', '=', account_depre_id),
                    # Same Owner
                    ('project_id', '=', asset.owner_project_id.id),
                    ('section_id', '=', asset.owner_section_id.id),
                ],
                order='id asc')
            if depre_lines:
                depre_line_dict = depre_lines[0].copy_data(default)[0]
                debit = sum(depre_lines.mapped('debit'))
                credit = sum(depre_lines.mapped('credit'))
                if debit > credit:
                    asset_line_dict['credit'] = debit - credit
                    asset_line_dict['debit'] = False
                else:
                    asset_line_dict['credit'] = False
                    asset_line_dict['debit'] = credit - debit
                depre_move_lines_dict.append(depre_line_dict)
            # Validation
            # if not asset_move_lines_dict:
            #     raise ValidationError(
            #         _('No Asset Value. Something went wrong!\nIt is likely '
            #         'that, the asset owner do not match with account move.'))
            return (asset_move_lines_dict, depre_move_lines_dict)

    @api.model
    def _prepare_asset_target_move(self, move_lines_dict, new_owner=None):
        if new_owner is None:
            new_owner = {}
        debit = sum(x['debit'] for x in move_lines_dict)
        credit = sum(x['credit'] for x in move_lines_dict)
        if not move_lines_dict:
            raise ValidationError(
                _('Error on function _prepare_asset_target_move.\n'
                  'Invalid or no journal entry in original asset.'))
        move_line_dict = move_lines_dict[0].copy()
        move_line_dict.update({
            'analytic_account_id': False,  # To refresh dimension
            'credit': debit,
            'debit': credit,
        })
        if new_owner:
            move_line_dict.update({
                'project_id':
                new_owner.get('owner_project_id', False),
                'section_id':
                new_owner.get('owner_section_id', False),
            })
        return move_line_dict
Exemple #3
0
class ConsumeStock(models.Model):
    _name = 'farm.consume.stock'

    state = fields.Selection([('draft', 'Draft'), ('confirmed', 'Confirmed')],
                             default='draft')
    type = fields.Selection([('farm', 'Farm'), ('yard', 'Yard')],
                            string='Distribution Type')
    origin = fields.Many2one(string='Origin',
                             comodel_name='stock.location')
    to_location = fields.Many2one(string='Destinity',
                                  comodel_name='stock.location')
    product_id = fields.Many2one(string='Product',
                                 comodel_name='product.product')
    lot_id = fields.Many2one(string='Lot', comodel_name='stock.production.lot')
    quantity = fields.Float(string='Quantity')
    date = fields.Date(string='Date', defaut=fields.Date.today())

    @api.multi
    @api.onchange('type')
    def onchange_type(self):
        for res in self:
            if res.type and res.type == 'farm':
                return {'domain': {'to_location': [('usage', '=', 'view')]}}
            else:
                return {'domain': {'to_location': [('usage', '!=', 'view')]}}

    @api.multi
    @api.onchange('origin')
    def onchange_location(self):
        for res in self:
            ids = []
            quants = self.env['stock.quant'].search([
                ('location_id', '=', res.origin.id),
                ('qty', '>', 0)
                ])
            for q in quants:
                ids.append(q.product_id.id)
            return {'domain': {'product_id': [('id', 'in', ids)]}}

    @api.multi
    @api.onchange('product_id')
    def onchange_product(self):
        for res in self:
            ids = []
            quants = self.env['stock.quant'].search([
                ('location_id', '=', res.origin.id),
                ('product_id', '=', res.product_id.id)])
            for q in quants:
                ids.append(q.lot_id.id)
            return {'domain': {
                        'lot_id': [('id', 'in', ids)]}}
    @api.multi
    @api.onchange('lot_id')
    def on_change_lot(self):
        for res in self:
            quants = self.env['stock.quant'].search([
                ('location_id', '=', res.origin.id),
                ('product_id', '=', res.product_id.id),
                ('lot_id', '=', res.lot_id.id)])
            total = 0
            for q in quants:
                total = total + q.qty
            res.quantity = total

    @api.multi
    def get_cost(self, lot, qty):
        cost = 0
        if lot and lot.unit_cost and lot.unit_cost > 0:
            cost = lot.unit_cost * qty
        else:
            if lot:
                quants_obj = self.env['stock.quant']
                quants = quants_obj.search([
                    ('lot_id', '=', lot.id)])
                ids = []
                for q in quants:
                    ids.append(q.id)
                moves = self.env['stock.move'].with_context({}).search([
                    ('quant_ids', 'in', ids),
                    ('picking_id', '!=', False)])
                amount = 0.0
                raw_qty = 0
                for mov in moves:
                    if mov.price_unit > 0:
                        amount += mov.price_unit * mov.product_qty
                        raw_qty = raw_qty + mov.product_qty
                if raw_qty > 0:
                    unit_price = amount/raw_qty
                    cost += qty * unit_price
                if cost == 0:
                    cost = lot.product_id.product_tmpl_id.list_price * qty
            else:
                cost = lot.product_id.product_tmpl_id.list_price * qty
        return cost

    @api.multi
    def confirm(self):
        quants_obj = self.env['stock.quant']
        for res in self:
            species = self.env['farm.specie'].search(
                [(True, '=', True)])
            remov_locs = []
            for specie in species:
                remov_locs.append(specie.removed_location.id)
            if res.type == 'farm':
                condition = ('farm', '=', res.to_location.id)
            else:
                condition = ('location', '=', res.to_location.id)
            afected_ani = self.env['farm.animal'].search([
                condition, ('location', 'not in', remov_locs)])
            afected_gro = self.env['farm.animal.group'].search([
                condition, ('state', '!=', 'sold'),
                ('location', 'not in', remov_locs)])
            afected_animals = [afected_gro, afected_ani]
            num_ani = len(afected_ani)
            for party in afected_gro:
                num_ani = num_ani + party.quantity
            cost = self.get_cost(res.lot_id, res.quantity)
            if num_ani > 0:
                cost_p_an = cost/num_ani
                for gro in afected_gro:
                    self.set_party_cost(gro, res.date, cost_p_an)
                for an in afected_ani:
                    self.set_animal_cost(an, res.date, cost_p_an)
            else:
                if res. type == 'farm':
                    farm = res.to_location
                else:
                    farm = self.get_farm(res.to_location)
                analitic_remain_ob = self.env['purchase.analitic.remain']
                analitic_remain = analitic_remain_ob.search([
                        ('farm', '=', farm.id)])
                if len(analitic_remain) == 0:
                    analitic_remain_ob.create({
                        'farm': farm.id,
                        'quantity': cost})
                else:
                    analitic_remain.quantity = analitic_remain.quantity\
                        + cost
            consumed_quants = False
            if res.lot_id:
                consumed_quants = quants_obj.search([
                        ('lot_id', '=', res.lot_id.id),
                        ('location_id', '=', res.origin.id)])
            if not consumed_quants:
                consumed_quants = quants_obj.search([
                    ('location_id', '=', res.origin.id)])
            consumed_goods = res.quantity
            for q in consumed_quants:
                if q.qty >= consumed_goods:
                    q.qty -= consumed_goods
                    consumed_goods = 0
                else:
                    consumed_goods -= q.qty
                    q.qty = 0
            res.state = 'confirmed'

    def get_farm(self, location):
        while(location.location_id.id != 1):
            location = location.location_id
        return location

    @api.multi
    def set_party_cost(self, party, date, cost_per_animal_day):
        company = self.env['res.company'].with_context({}).search([
            ('id', '=', 1)])
        journal = self.env['account.analytic.journal'].with_context(
            {}).search([('code', '=', 'PUR')])
        analytic_line_obj = self.env['account.analytic.line']
        analytic_line_obj.create({
            'name': 'consum',
            'date': date,
            'amount': -(cost_per_animal_day * party.quantity),
            'unit_amount': party.quantity,
            'account_id': party.account.id,
            'general_account_id': company.feed_account.id,
            'journal_id': journal.id,
            })

    @api.multi
    def set_animal_cost(self, animal, date, cost_per_animal_day):
        company = self.env['res.company'].with_context({}).search([
            ('id', '=', animal.farm.company_id.id)])
        journal = self.env['account.analytic.journal'].with_context(
            {}).search([('code', '=', 'PUR')])
        analytic_line_obj = self.env['account.analytic.line']
        analytic_line_obj.create({
            'name': 'consum',
            'date': date,
            'amount': -cost_per_animal_day,
            'unit_amount': 1,
            'account_id': animal.account.id,
            'general_account_id': company.feed_account.id,
            'journal_id': journal.id,
            })
            
Exemple #4
0
class AccountAssetAsset(models.Model):
    _name = 'account.asset.asset'
    _description = 'Asset/Revenue Recognition'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

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

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

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

    @api.model
    def _cron_generate_entries(self):
        self.compute_generated_entries(datetime.today())

    @api.model
    def compute_generated_entries(self, date, asset_type=None):
        # Entries generated : one by grouped category and one by asset from ungrouped category
        created_move_ids = []
        type_domain = []
        if asset_type:
            type_domain = [('type', '=', asset_type)]

        ungrouped_assets = self.env['account.asset.asset'].search(
            type_domain +
            [('state', '=', 'open'), ('category_id.group_entries', '=',
                                      False)])
        created_move_ids += ungrouped_assets._compute_entries(
            date, group_entries=False)

        for grouped_category in self.env['account.asset.category'].search(
                type_domain + [('group_entries', '=', True)]):
            assets = self.env['account.asset.asset'].search([
                ('state', '=', 'open'),
                ('category_id', '=', grouped_category.id)
            ])
            created_move_ids += assets._compute_entries(date,
                                                        group_entries=True)
        return created_move_ids

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

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

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

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

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

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

            undone_dotation_number = self._compute_board_undone_dotation_nb(
                depreciation_date, total_days)

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

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

        return True

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

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

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

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

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

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

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

    @api.multi
    @api.depends('depreciation_line_ids.move_id')
    def _entry_count(self):
        for asset in self:
            res = self.env['account.asset.depreciation.line'].search_count([
                ('asset_id', '=', asset.id), ('move_id', '!=', False)
            ])
            asset.entry_count = res or 0

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

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

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

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

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

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

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

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

    @api.multi
    def open_entries(self):
        move_ids = []
        for asset in self:
            for depreciation_line in asset.depreciation_line_ids:
                if depreciation_line.move_id:
                    move_ids.append(depreciation_line.move_id.id)
        return {
            'name': _('Journal Entries'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'account.move',
            'view_id': False,
            'type': 'ir.actions.act_window',
            'domain': [('id', 'in', move_ids)]
        }
class AccountSoldCheck(models.Model):
    _name = 'account.sold.check'

    @api.depends('account_third_check_ids', 'interests', 'commission',
                 'account_third_check_ids')
    def _compute_amount(self):
        for sold_check in self:
            checks_amount = sum(
                check.amount for check in sold_check.account_third_check_ids)
            sold_check.amount = checks_amount - sold_check.interests - sold_check.commission

    name = fields.Char('Nombre', readonly=True)
    partner_id = fields.Many2one('res.partner', 'Partner')
    bank_account_id = fields.Many2one('account.journal', 'Cuenta bancaria')
    account_id = fields.Many2one('account.account',
                                 'Cuenta para la acreditacion del dinero',
                                 required=True)
    journal_id = fields.Many2one('account.journal', 'Diario')
    date = fields.Date('Fecha de emision', required=True)
    commission = fields.Monetary('Importe de la comision')
    interests = fields.Monetary('Importe de los intereses')
    commission_account_id = fields.Many2one(
        'account.account',
        'Cuenta para las comisiones',
    )
    interest_account_id = fields.Many2one('account.account',
                                          'Cuenta para los intereses')
    amount = fields.Monetary('Total cobrado', compute=_compute_amount)
    account_third_check_ids = fields.Many2many(
        'account.third.check',
        'third_check_sold_check_rel',
        'sold_check_id',
        'third_check_id',
        string='Cheques',
    )
    move_id = fields.Many2one('account.move',
                              'Asiento contable',
                              readonly=True)
    state = fields.Selection([('canceled', 'Cancelado'), ('draft', 'Borrador'),
                              ('sold', 'Vendido')],
                             default='draft',
                             string='Estado',
                             readonly=True)
    company_id = fields.Many2one('res.company', 'Compania')
    currency_id = fields.Many2one(
        'res.currency',
        'Moneda',
    )

    @api.constrains('interests', 'commission')
    def constrain_amount(self):
        if self.interests < 0 or self.commission < 0 or self.amount < 0:
            raise ValidationError("Los importes no pueden ser negativos")

    @api.model
    def create(self, values):
        values['name'] = self.env['ir.sequence'].next_by_code(
            'account.sold.check.sequence')
        return super(AccountSoldCheck, self).create(values)

    @api.constrains('account_third_check_ids')
    def check_currency(self):
        """ Valida que no haya cheques con distintas monedas """
        for sold_check in self:
            currency = sold_check.account_third_check_ids.mapped('currency_id')
            if len(currency) > 1:
                raise ValidationError(
                    "No se pueden vender cheques de distintas monedas"
                    " en el mismo documento de venta de cheques")

            sold_check.account_third_check_ids.sold_check_contraints()

    @api.multi
    def post(self):
        """ Confirma la venta de cheques cambiando el estado de los cheques y crea el asiento correspondiente """
        if not self.account_third_check_ids:
            raise ValidationError("No se puede validar una boleta sin cheques")
        for sold_check in self:
            sold_check._check_fields()
            sold_check.write({
                # Ya validamos en el constraint que la moneda es unica
                'currency_id':
                sold_check.account_third_check_ids.mapped('currency_id').id,
                'state':
                'sold'
            })
            move = sold_check._create_move(sold_check.name)
            sold_check.move_id = move.id
            sold_check.account_third_check_ids.post_sold_check()

    def draft(self):
        """ Vuelve una la venta de cheques a estado borrador """
        self.ensure_one()
        self.state = 'draft'

    def cancel(self):
        """ Cancela la venta de cheques y elimina el asiento """

        self.ensure_one()
        # Cancelamos y borramos el asiento
        self.move_id.button_cancel()
        self.move_id.unlink()

        # Revertimos el estado de los cheques
        self.account_third_check_ids.cancel_sold_check()
        self.state = 'canceled'

    def _create_move(self, name):
        """
        Crea el asiento de la venta de cheques
        :param name: Referencia que se utilizará en el asiento
        :return: account.move creado
        """

        journal = self.bank_account_id or self.journal_id
        vals = {
            'date': self.date,
            'ref': 'Venta de cheques: {}'.format(name),
            'journal_id': journal.id,
        }
        move = self.env['account.move'].create(vals)
        account = self.account_id

        # Creamos las lineas del debe, puede haber hasta 3 (si tiene comision e intereses)
        if self.amount:
            amount, amount_currency = self._get_multicurrency_values(
                self.amount)
            self._create_move_lines(move,
                                    amount_currency,
                                    account,
                                    debit=amount)

        if self.commission:
            commission, amount_currency = self._get_multicurrency_values(
                self.commission)
            self._create_move_lines(move,
                                    amount_currency,
                                    self.commission_account_id,
                                    debit=commission)

        if self.interests:
            interests, amount_currency = self._get_multicurrency_values(
                self.interests)
            self._create_move_lines(move,
                                    amount_currency,
                                    self.interest_account_id,
                                    debit=interests)

        # Creamos la linea del haber
        amount, amount_currency = self._get_multicurrency_values(
            self.amount + self.interests + self.commission)
        self._create_move_lines(
            move,
            -amount_currency,
            self.env.user.company_id.third_check_account_id,
            credit=amount)

        move.post()

        return move

    def _create_move_lines(self,
                           move,
                           amount_currency,
                           account,
                           debit=0.0,
                           credit=0.0):
        """
        Crea una move line de la venta de cheques y las asocia al move
        :param move: account.move - Asiento a relacionar las move_lines creadas
        :param amount_currency: Importe en moneda original
        :param account: Cuenta contable de la linea del asiento
        :param debit: Importe en el haber de la move line
        :param credit: Importe en el haber de la move line
        :return: account.move.line creada
        """

        company_currency = self.env.user.company_id.currency_id
        journal = self.bank_account_id or self.journal_id
        if not account:
            raise ValidationError(
                "Falta configurar alguna cuenta contable para realizar esta tarea"
            )

        move_line_vals = {
            'move_id':
            move.id,
            'debit':
            debit,
            'credit':
            credit,
            'amount_currency':
            amount_currency,
            'name':
            move.ref,
            'account_id':
            account.id,
            'journal_id':
            journal.id,
            'currency_id':
            self.currency_id != company_currency and self.currency_id.id
            or False,
            'ref':
            move.ref
        }
        return self.env['account.move.line'].with_context(
            check_move_validity=False).create(move_line_vals)

    def _get_multicurrency_values(self, amount):
        """
        Devuelve el importe en multi moneda para la fecha de la venta de cheques
        :param amount: Importe a calcular en multi moneda
        :returns:  amount_currency - Importe en la moneda de la venta de cheque
                   debit - Importe para la move line

        """
        move_line_proxy = self.env['account.move.line']
        company = self.env.user.company_id

        debit, credit, amount_currency, currency_id = move_line_proxy.with_context(date=self.date). \
            compute_amount_fields(amount, self.currency_id, company.currency_id)

        return debit, amount_currency

    def _check_fields(self):
        """ Valida que el documento tenga la información necesaria para ser validado """
        self.ensure_one()
        if not (self.partner_id or self.bank_account_id):
            raise ValidationError(
                "Debe seleccionar un partner o una cuenta bancaria para validar el documento"
            )
Exemple #6
0
class CashFlowReport(models.TransientModel):
    _name = 'account.cash.flow'
    _description = u'Cash Flow Report'

    @api.one
    def calc_final_amount(self):
        balance = 0
        for line in self.line_ids:
            balance += line.amount
        balance += self.start_amount
        self.final_amount = balance

    company_id = fields.Many2one('res.company', string="Empresa")
    start_date = fields.Date(string="Start Date",
                             required=True,
                             default=fields.date.today())
    end_date = fields.Date(string="End Date",
                           required=True,
                           default=fields.date.today() +
                           datetime.timedelta(6 * 365 / 12))
    start_amount = fields.Float(string="Initial Value",
                                digits_compute=dp.get_precision('Account'))
    final_amount = fields.Float(string="Total",
                                compute="calc_final_amount",
                                digits_compute=dp.get_precision('Account'))
    line_ids = fields.One2many("account.cash.flow.line",
                               "cashflow_id",
                               string="Cash Flow Lines")

    @api.multi
    def calculate_liquidity(self):
        accs = self.env['account.account'].with_context(state='posted').search(
            [('type', '=', 'liquidity'),
             ('company_id', '=', self.company_id.id)])
        liquidity_lines = []
        for acc in accs:
            if acc.balance != 0:
                liquidity_lines.append({
                    'name': acc.name,
                    'cashflow_id': self.id,
                    'account_id': acc.id,
                    'debit': acc.credit,
                    'credit': acc.debit,
                    'amount': acc.balance,
                })
        return liquidity_lines

    @api.multi
    def calculate_moves(self):
        moveline_obj = self.env['account.move.line']
        moveline_ids = moveline_obj.search([
            '|',
            ('account_id.type', '=', 'receivable'),
            ('account_id.type', '=', 'payable'),
            ('reconcile_id', '=', False),
            ('state', '!=', 'draft'),
            ('company_id', '=', self.company_id.id),
            ('date_maturity', '<=', self.end_date),
        ])
        moves = []
        for move in moveline_ids:
            debit, credit = move.credit, move.debit
            amount = move.debit - move.credit
            if move.reconcile_partial_id:
                move_ids = moveline_obj.search([
                    ('reconcile_partial_id', '=', move.reconcile_partial_id.id)
                ])
                debit = sum(line.credit for line in move_ids)
                credit = sum(line.debit for line in move_ids)
                amount = credit - debit

            moves.append({
                'name': move.ref,
                'cashflow_id': self.id,
                'partner_id': move.partner_id.id,
                'journal_id': move.journal_id.id,
                'account_id': move.account_id.id,
                'date': move.date_maturity,
                'debit': debit,
                'credit': credit,
                'amount': amount,
            })
        return moves

    @api.multi
    def action_calculate_report(self):
        self.write({'line_ids': [(5, 0, 0)]})
        balance = self.start_amount
        liquidity_lines = self.calculate_liquidity()
        move_lines = self.calculate_moves()

        move_lines.sort(
            key=lambda x: datetime.datetime.strptime(x['date'], '%Y-%m-%d'))

        for lines in liquidity_lines + move_lines:
            balance += lines['credit'] - lines['debit']
            lines['balance'] = balance
            self.env['account.cash.flow.line'].create(lines)
class PurchaseRequestLine(models.Model):

    _name = "purchase.request.line"
    _description = "Purchase Request Line"
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    @api.multi
    @api.depends('product_id', 'name', 'product_uom_id', 'product_qty',
                 'analytic_account_id', 'date_required', 'specifications')
    def _compute_is_editable(self):
        for rec in self:
            if rec.request_id.state in ('to_approve', 'to_department_manager_approved','to_accountant_manager_approved','approved', 'rejected'):
                rec.is_editable = False
            else:
                rec.is_editable = True

    @api.multi
    def _compute_supplier_id(self):
        for rec in self:
            if rec.product_id:
                if rec.product_id.seller_ids:
                    rec.supplier_id = rec.product_id.seller_ids[0].name

    product_id = fields.Many2one(
        'product.product', 'Product',
        domain=[('purchase_ok', '=', True)],
        track_visibility='onchange')
    name = fields.Char('Description', size=256, required=True, 
                       track_visibility='onchange')
    product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure',
                                     track_visibility='onchange')
    product_qty = fields.Float('Quantity', track_visibility='onchange', default = 1,
                               digits_compute=dp.get_precision(
                                   'Product Unit of Measure'))
    product_price = fields.Float('Price', track_visibility='onchange')
    accepted = fields.Boolean('Accepted', track_visibility='onchange')
    request_id = fields.Many2one('purchase.request',
                                 'Purchase Request',
                                 ondelete='cascade', readonly=True)
    company_id = fields.Many2one('res.company',
                                 related='request_id.company_id',
                                 string='Company',
                                 store=True, readonly=True)
    analytic_account_id = fields.Many2one('account.analytic.account',
                                          'Analytic Account',
                                          track_visibility='onchange')
    requested_by = fields.Many2one('res.users',
                                   related='request_id.requested_by',
                                   string='Requested by',
                                   store=True, readonly=True)
    assigned_to = fields.Many2one('res.users',
                                  related='request_id.assigned_to',
                                  string='Assigned to',
                                  store=True, readonly=True)
    assigned_to_3 = fields.Many2one('res.users',
                                  related='request_id.assigned_to_3',
                                  string='Assigned to',
                                  store=True, readonly=True)
    date_start = fields.Date(related='request_id.date_start',
                             string='Request Date', readonly=True,
                             store=True)
    description = fields.Text(related='request_id.description',
                              string='Description', readonly=True,
                              store=True)
    origin = fields.Char(related='request_id.origin',
                         size=32, string='Source Document', readonly=True,
                         store=True)
    date_required = fields.Date(string='Request Date', required=True,
                                track_visibility='onchange',
                                default=fields.Date.context_today)
    is_editable = fields.Boolean(string='Is editable',
                                 compute="_compute_is_editable",
                                 readonly=True)
    specifications = fields.Text(string='Specifications')
    request_state = fields.Selection(string='Request state',
                                     readonly=True,
                                     related='request_id.state',
                                     selection=_STATES,
                                     store=True)
    request_stage = fields.Selection(string='Request stage',
                                     readonly=True,
                                     related='request_id.stage',
                                     selection=_STAGES,
                                     store=True)
    
    supplier_id = fields.Many2one('res.partner',
                                  string='Preferred supplier',
                                  compute="_compute_supplier_id")

    procurement_id = fields.Many2one('procurement.order',
                                     'Procurement Order',
                                     readonly=True)
    
    attachment_ids = fields.Many2many('ir.attachment', 'class_ir_attachments_rel', 'class_id', 
                                      'attachment_id', 'Attachments')
    price_total = fields.Float( string='Total',
                                track_visibility='onchange', 
                                compute="_compute_amount",
                                store=True)
    is_accepted = fields.Boolean(string="Is accepted",
                                 compute="_compute_is_accepted",
                                 readonly=True)
    
    stock_warehouse = fields.Selection(selection=_WAREHOUSES,
                             string='Stock')
    
    is_warehouse_notes = fields.Boolean(string="Is Warehouse Notes",
                                 compute="_compute_is_warehouse_notes",
                                 readonly=True)
    
    is_usr = fields.Boolean(string="Is Requested by User",
                                 compute="_compute_is_usr",
                                 readonly=True)
    
    warehouse_manager_notes = fields.Text('Warehouse manager notes')
    
    def _compute_is_accepted(self):
        for rec in self:
            if rec.assigned_to == self.env['res.users'].browse(self.env.uid):
                rec.is_accepted = True
            else:
                if rec.assigned_to:
                    rec.is_accepted = False
                elif rec.assigned_to == 0:
                    rec.is_accepted = True
                else:
                    rec.is_accepted = True
    
    @api.onchange('product_id')
    def onchange_product_id(self):
        if self.product_id:
            #name = self.product_id.name
            #if self.product_id.code:
             #   name = '[%s] %s' % (name, self.product_id.code)
            #if self.product_id.description_purchase:
             #   name += '\n' + self.product_id.description_purchase
            self.product_uom_id = self.product_id.uom_id.id
            #self.product_qty = 1
            #self.name = name
               
    def _compute_is_warehouse_notes(self):
        for rec in self:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_82'):
                    rec.is_warehouse_notes = True
                else:
                    rec.is_warehouse_notes= False
    
          
    def _compute_is_usr(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_usr = True
            else:
                rec.is_usr = False
                    

    @api.one
    @api.depends('product_qty', 'product_price')
    def _compute_amount(self):
        if self.product_qty > 0:
            self.price_total = self.product_price * self.product_qty
Exemple #8
0
class crm_lead(models.Model):
    _inherit = 'crm.lead'

    def _get_new_code(self, cr, uid, context=None):
        today = old_fields.date.context_today(self, cr, uid, context=context)
        d = fields.Date.from_string(today)
        name = d.strftime('SE%y%m%d')
        ids = self.search(
            cr,
            uid,
            [('create_date', '>=', d.strftime(DEFAULT_SERVER_DATE_FORMAT))],
            context=context)
        if len(ids) > 0:
            name = name + ('%02i' % (len(ids) + 1))
        return name

    sales_funnel_type = fields.Selection(related='stage_id.sales_funnel_type',
                                         readonly=True)
    sale_order_id = fields.Many2one('sale.order', 'Quotation \ Sale Order')
    sale_order_lines = fields.One2many('sale.order.line',
                                       'order_id',
                                       string='Order lines',
                                       related='sale_order_id.order_line',
                                       readonly=False)
    pricelist_id = fields.Many2one('product.pricelist',
                                   'Pricelist',
                                   related='sale_order_id.pricelist_id',
                                   readonly=False)
    date_order = fields.Datetime(string='Date order',
                                 related='sale_order_id.date_order',
                                 readonly=False)
    fiscal_position = fields.Many2one('account.fiscal.position',
                                      string='Fiscal Position',
                                      related='sale_order_id.fiscal_position',
                                      readonly=False)

    sale_order_state = fields.Selection('Sale order status',
                                        related='sale_order_id.state')
    color = fields.Integer('Color index', related='section_id.color')
    is_proposal_sent = fields.Boolean('Proposal sent', default=False)
    is_proposal_confirmed = fields.Boolean('Proposal confirmed', default=False)
    project_id = fields.Many2one('project.project', 'Project')
    contract_id = fields.Many2one('account.analytic.account',
                                  'Contract',
                                  related='project_id.analytic_account_id')

    stage_closed_id = fields.Many2one('crm.case.stage',
                                      'Last stage',
                                      help='Stage before close case')

    date_closed_custom = fields.Datetime(string='Date closed (custom)')

    project_start_date = fields.Date('Project start date')
    project_end_date = fields.Date('Project end date')

    def _check_dates(self, cr, uid, ids, context=None):
        for leave in self.read(cr,
                               uid,
                               ids, ['project_start_date', 'project_end_date'],
                               context=context):
            if leave['project_start_date'] and leave['project_end_date']:
                if leave['project_start_date'] > leave['project_end_date']:
                    return False
        return True

    _constraints = [
        (_check_dates,
         'Error! project start-date must be lower then project end-date.',
         ['project_start_date', 'project_end_date'])
    ]

    @api.one
    @api.depends('date_closed_custom')
    def _get_deal_time(self):
        res = None
        start_date = self.create_date or old_fields.datetime.now()
        end_date = self.date_closed_custom or old_fields.datetime.now()
        d = datetime.strptime(
            end_date, DEFAULT_SERVER_DATETIME_FORMAT) - datetime.strptime(
                start_date, DEFAULT_SERVER_DATETIME_FORMAT)
        res = d.days + 1
        self.deal_time = res

    deal_time = fields.Integer(string='Deal time',
                               compute=_get_deal_time,
                               store=True)

    @api.model
    def update_deal_time(self):
        self.search([('sales_funnel_type', 'not in', ['won', 'lost'])
                     ])._get_deal_time()
        self.search([('sales_funnel_type', 'not in', ['won', 'lost'])
                     ])._get_last_action_time()

    @api.one
    @api.depends('date_action', 'date_last_stage_update')
    def _get_last_action_time(self):
        res = None
        start_date = self.date_action or self.date_last_stage_update or old_fields.datetime.now(
        )
        try:
            start_date = datetime.strptime(start_date,
                                           DEFAULT_SERVER_DATETIME_FORMAT)
        except:
            start_date = datetime.strptime(start_date,
                                           DEFAULT_SERVER_DATE_FORMAT)
        end_date = old_fields.datetime.now()
        end_date = datetime.strptime(end_date, DEFAULT_SERVER_DATETIME_FORMAT)

        d = end_date - start_date
        res = d.days
        self.last_action_time = res

    last_action_time = fields.Integer(string='Last Action',
                                      compute=_get_last_action_time,
                                      store=True)

    @api.one
    def action_create_sale_order(self):
        # TODO
        pass

    @api.multi
    def action_create_sale_case(self):  # OLD
        #assert len(self) == 1, 'This option should only be used for a single id at a time.'
        sale_case_id = None
        for r in self:
            if r.contract_ids or not r.partner_id or r.type != 'lead':
                continue
            vals = {
                'lead_id': r.id,
                'partner_id': r.partner_id.id,
                'section_id': r.section_id and r.section_id.id or False,
                'type': 'contract',
                'state': 'lead'
            }
            sale_case_id = self.env['account.analytic.account'].create(vals)
            sale_case_id.write({'name': '%s %s' % (sale_case_id.name, r.name)})
            #r.type = 'opportunity'

        if len(self) > 1 or not sale_case_id:
            return True

        form = self.env.ref(
            'account_analytic_analysis.account_analytic_account_form_form',
            False)

        return {
            'name': _('Sale Case'),
            'view_type': 'form',
            'view_mode': 'tree, form, kanban',
            'res_model': 'account.analytic.account',
            'res_id': sale_case_id and int(sale_case_id),
            #'view_id': False,
            'views': [(form.id, 'form')],
            'type': 'ir.actions.act_window',
        }

    @api.one
    def set_sales_funnel(self, sales_funnel_type):
        stage_ids = self.env['crm.case.stage'].search([
            ('sales_funnel_type', '=', sales_funnel_type),
            ('section_ids', '=', self.section_id.id), '|',
            ('type', '=', self.type), ('type', '=', 'both')
        ])
        stage_ids = sorted(stage_ids, key=lambda x: x.sequence)
        if not stage_ids:
            if not self.section_id:
                raise exceptions.Warning('You have to specify sales team')
            raise exceptions.Warning(
                'There is no stage of type %s. Please contact your administrator'
                % sales_funnel_type)
        self.stage_id = stage_ids[0]

    @api.one
    def action_set_state_quotation(self):
        self.set_sales_funnel('quotation')

    @api.one
    def action_set_state_negotiation(self):
        self.is_proposal_sent = True
        self.set_sales_funnel('negotiation')

    @api.one
    def action_set_state_sales_lost(self):
        self.set_sales_funnel('lost')

    @api.v7
    def action_send_proposal(self, cr, uid, ids, context=None):
        assert len(
            ids
        ) == 1, 'This option should only be used for a single id at a time.'
        sale_case = self.browse(cr, uid, ids, context=context)[0]
        if not sale_case.sale_order_id.order_line:
            raise exceptions.Warning('You have to specify order lines')

        ir_model_data = self.pool.get('ir.model.data')
        try:
            template_id = ir_model_data.get_object_reference(
                cr, uid, 'sale_mediation_custom',
                'email_template_proposal_lead')[1]
        except ValueError:
            template_id = False
        try:
            compose_form_id = ir_model_data.get_object_reference(
                cr, uid, 'mail', 'email_compose_message_wizard_form')[1]
        except ValueError:
            compose_form_id = False
        ctx = dict()
        ctx.update({
            'default_model': 'crm.lead',
            'default_res_id': sale_case.id,
            'default_use_template': bool(template_id),
            'default_template_id': template_id,
            'default_composition_mode': 'comment',
            'sale_case_id': sale_case.id,
            'mark_proposal_as_sent': True
        })
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form_id, 'form')],
            'view_id': compose_form_id,
            'target': 'new',
            'context': ctx,
        }

    @api.v7
    def action_send_proposal_quick(self, cr, uid, ids, context=None):
        res = self.pool['crm.lead'].action_send_proposal(cr,
                                                         uid,
                                                         ids,
                                                         context=context)
        compose_ctx = res.get('context')
        compose_id = self.pool['mail.compose.message'].create(
            cr, uid, {}, context=compose_ctx)
        self.pool['mail.compose.message'].send_mail(cr,
                                                    uid, [compose_id],
                                                    context=compose_ctx)

    #@api.v7 # workflow handler doesn't work with this decorator
    def action_set_state_sale_won(self, cr, uid, ids, context={}):
        assert len(
            ids
        ) == 1, 'This option should only be used for a single id at a time.'

        r = self.browse(cr, uid, ids, context=context)[0]
        r.write({'is_proposal_confirmed': True})

        if r.project_id:
            r.set_sales_funnel('won')
            return True

        if not r.project_start_date or not r.project_end_date:
            raise exceptions.Warning('You have to specify project interval')

        r.sale_order_id.action_button_confirm()

        sale_order_name = r.sale_order_id.name
        if not sale_order_name.endswith(' SO'):
            m = re.match('SE(\d*)(.*)', sale_order_name)

            if m:
                sale_order_name = '%s SO%s' % (m.group(1), m.group(2))
            else:
                sale_order_name = '%s SO' % sale_order_name
            r.sale_order_id.write({'name': sale_order_name})

        m = re.match('SE(\d*)(.*)', r.name)

        name = r.name
        if m:
            name = 'PE%s (SE)%s' % (m.group(1), m.group(2))
        vals = {
            'name': name,
            'partner_id': r.partner_id.id,
            'sale_case_id': r.id,
            'date_start': r.project_start_date,
            'date': r.project_end_date,
        }
        project_id = self.pool['project.project'].create(
            cr, uid, vals, context=context.copy())
        r.write({'project_id': project_id})
        r.set_sales_funnel('won')

        data_obj = self.pool.get('ir.model.data')
        form_view_id = data_obj._get_id(cr, uid, 'project', 'edit_project')
        form_view = data_obj.read(cr, uid, form_view_id, ['res_id'])

        return {
            'name': _('Project'),
            'view_type': 'form',
            'view_mode': 'kanban, tree, form',
            'res_model': 'project.project',
            'res_id': int(project_id),
            #'view_id': False,
            'views': [(form_view['res_id'], 'form')],
            'type': 'ir.actions.act_window',
        }

    @api.v7
    def edit_proposal(self, cr, uid, ids, context=None):
        r = self.browse(cr, uid, ids[0], context)
        return self.pool['website_proposal.proposal'].edit_proposal(
            cr, uid, [r.proposal_id.id], context=context)

    @api.v7
    def open_proposal(self, cr, uid, ids, context=None):
        r = self.browse(cr, uid, ids[0], context)
        return self.pool['website_proposal.proposal'].open_proposal(
            cr, uid, [r.proposal_id.id], context=context)

    @api.one
    def copy(self, default=None):
        default = dict(default or {})
        default['name'] = _('%s (copy)') % self.name
        new_id = super(crm_lead, self).copy(default)
        if self.proposal_id:
            proposal_default = {'res_id': new_id}
            new_proposal_id = self.proposal_id.copy(proposal_default)
        return new_id

    @api.one
    def try_update_stage(self, stage):
        old = self.stage_id.sales_funnel_type
        new = stage.sales_funnel_type
        if not (old and new):
            return {
                'warning':
                '"Sales funnel" field has to be specified for sale stage!'
            }

        if old == 'lost' and new != 'lead':
            return {
                'warning':
                'From dead stage you can move sale case only to lead stage'
            }
        if new == 'quotation':
            if not self.partner_id:
                return {'warning': 'You have to specify Customer'}
            if not self.proposal_id:
                return {'warning': 'You have to create proposal'}
        if new == 'negotiation':
            #if old!='quotation':
            #    return {'warning': 'You can move to negotiation only after quotation'}
            if not self.is_proposal_sent:
                return {'warning': 'You have to send proposal to client'}
        if new == 'won':
            #if old!='negotiation':
            #    return {'warning': 'You have to pass Negotiation stages before move sale case to Won'}
            if not self.is_proposal_confirmed:
                return {'warning': 'Quotation is not confirmed by customer'}

        return {}

    @api.multi
    def write(self, vals):
        if 'stage_id' in vals:
            new_stage = self.env['crm.case.stage'].browse(vals['stage_id'])
            for r in self:
                res = r.try_update_stage(new_stage)[0]
                if res.get('warning'):
                    raise exceptions.Warning(res.get('warning'))
                if new_stage.sales_funnel_type in ['won', 'lost']:
                    vals['stage_closed_id'] = r.stage_id.id
                    vals['date_closed_custom'] = fields.datetime.now()
        if 'user_id' in vals:
            for r in self:
                if r.sale_order_id and (
                        not r.sale_order_id.user_id
                        or r.sale_order_id.user_id.id != vals['user_id']):
                    r.sale_order_id.user_id = vals['user_id']
        result = super(crm_lead, self).write(vals)
        if 'sale_order_id' not in vals:
            self.create_sale_order(raise_error=False)
        return result

    @api.model
    def create(self, vals):
        result = super(crm_lead, self).create(vals)
        sale_order = result.create_sale_order(raise_error=False)
        return result

    _columns = {
        'proposal_id':
        old_fields.function(_get_proposal_id,
                            type='many2one',
                            obj='website_proposal.proposal',
                            string='Proposal'),  # to delete
    }
    _defaults = {
        'name': _get_new_code,
    }

    @api.multi
    def create_sale_order(self, raise_error=True):
        sale_order = None
        for r in self:
            if r.sale_order_id:
                sale_order = r.sale_order_id
                continue

            partner = r.partner_id
            if not partner:
                if raise_error:
                    raise exceptions.Warning('You have to specify Customer')
                else:
                    continue

            pricelist = partner.property_product_pricelist.id
            partner_addr = partner.address_get(
                ['default', 'invoice', 'delivery', 'contact'])
            if False in partner_addr.values():
                if raise_error:
                    raise osv.except_osv(
                        _('Insufficient Data!'),
                        _('No address(es) defined for this customer.'))
                else:
                    continue

            fpos = partner.property_account_position and partner.property_account_position.id or False
            payment_term = partner.property_payment_term and partner.property_payment_term.id or False

            vals = {
                'name': '%s' % r.name,
                'origin': _('Opportunity: %s') % str(r.id),
                'section_id': r.section_id and r.section_id.id or False,
                'categ_ids':
                [(6, 0, [categ_id.id for categ_id in r.categ_ids])],
                'partner_id': partner.id,
                'user_id': r.user_id.id,
                'pricelist_id': pricelist,
                'partner_invoice_id': partner_addr['invoice'],
                'partner_shipping_id': partner_addr['delivery'],
                'date_order': old_fields.datetime.now(),
                'fiscal_position': fpos,
                'payment_term': payment_term,
            }
            sale_order = self.env['sale.order'].create(vals)
            r.write({
                'sale_order_id': sale_order.id,
                'ref': 'sale.order,%s' % sale_order.id,
            })
        return sale_order
Exemple #9
0
class SidDatos(models.Model):
    _name = 'financiera.sid.datos'

    _order = "id desc"
    name = fields.Char('Nombre para mostrar')
    partner_id = fields.Many2one("res.partner", "Cliente")
    id_tramite_principal = fields.Char("Id tramite principal")
    id_tramite_tarjeta_reimpresa = fields.Integer(
        "Id tramite tarjeta reimpresa")
    ejemplar = fields.Char("Ejemplar")
    vencimiento = fields.Date("Vencimiento")
    emision = fields.Date("Emision")
    apellido = fields.Char("Apellido")
    nombres = fields.Char("Nombres")
    fecha_nacimiento = fields.Date("Fecha nacimiento")
    cuil = fields.Char("CUIT")
    calle = fields.Char("Calle")
    numero = fields.Char("Numero")
    piso = fields.Char("Piso")
    departamento = fields.Char("Departamento")
    codigo_postal = fields.Char("Codigo postal")
    barrio = fields.Char("Barrio")
    monoblock = fields.Char("Monoblock")
    ciudad = fields.Char("Ciudad")
    municipio = fields.Char("Municipio")
    provincia = fields.Char("Provincia")
    pais = fields.Char("Pais")
    codigo_fallecido = fields.Integer("Codigo fallecido")
    mensaje_fallecido = fields.Char("Mensaje fallecido")
    id_ciudadano = fields.Char("Id ciudadano")
    codigo = fields.Integer("Codigo")
    mensaje = fields.Char("Mensaje")
    company_id = fields.Many2one('res.company',
                                 'Empresa',
                                 related='partner_id.company_id',
                                 readonly=True)

    @api.model
    def create(self, values):
        rec = super(SidDatos, self).create(values)
        rec.update({
            'name': 'SID/DNI/' + str(rec.id).zfill(8),
        })
        return rec

    @api.model
    def from_dict(self, obj, partner_id):
        print("SidDatos:from_dict")
        print("self: ", self)
        print("partner_id: ", partner_id)
        rec = False
        if isinstance(obj, dict):
            values = {
                'id_tramite_principal':
                from_str(obj.get(u"id_tramite_principal")),
                'id_tramite_tarjeta_reimpresa':
                int(obj.get(u"id_tramite_tarjeta_reimpresa")),
                'ejemplar':
                from_str(obj.get(u"ejemplar")),
                'vencimiento':
                from_datetime(obj.get(u"vencimiento")),
                'emision':
                from_datetime(obj.get(u"emision")),
                'apellido':
                from_str(obj.get(u"apellido")),
                'nombres':
                from_str(obj.get(u"nombres")),
                'fecha_nacimiento':
                from_datetime(obj.get(u"fecha_nacimiento")),
                'cuil':
                from_str(obj.get(u"cuil")),
                'calle':
                from_str(obj.get(u"calle")),
                'numero':
                from_str(obj.get(u"numero")),
                'piso':
                from_str(obj.get(u"piso")),
                'departamento':
                from_str(obj.get(u"departamento")),
                'codigo_postal':
                from_str(obj.get(u"codigo_postal")),
                'barrio':
                from_str(obj.get(u"barrio")),
                'monoblock':
                from_str(obj.get(u"monoblock")),
                'ciudad':
                from_str(obj.get(u"ciudad")),
                'municipio':
                from_str(obj.get(u"municipio")),
                'provincia':
                from_str(obj.get(u"provincia")),
                'pais':
                from_str(obj.get(u"pais")),
                'codigo_fallecido':
                from_int(obj.get(u"codigo_fallecido")),
                'mensaje_fallecido':
                from_str(obj.get(u"mensaje_fallecido")),
                'id_ciudadano':
                from_str(obj.get(u"id_ciudadano")),
                'codigo':
                from_int(obj.get(u"codigo")),
                'mensaje':
                from_str(obj.get(u"mensaje")),
                'partner_id':
                partner_id,
            }
            rec = self.env['financiera.sid.datos'].create(values)
        return rec
Exemple #10
0
class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    def _calc_line_base_price(self, cr, uid, line, context=None):
        price = line.price_unit
        #if line.type == 'child':
        price = price * (1 - (line.discount or 0.0) / 100.0)
        if line.is_discount:
            price = price * (1 - (line.partner_discount or 0.0) / 100.0)
        return price

    def _calc_line_quantity(self, cr, uid, line, context=None):
        return line.product_uom_qty
        #return line.product_uom_qty * line.duration

    def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
        tax_obj = self.pool.get('account.tax')
        cur_obj = self.pool.get('res.currency')
        res = {}
        if context is None:
            context = {}
        for line in self.browse(cr, uid, ids, context=context):
            price = self._calc_line_base_price(cr, uid, line, context=context)
            qty = self._calc_line_quantity(cr, uid, line, context=context)
            taxes = tax_obj.compute_all(cr, uid, line.tax_id, price, qty,
                                        line.product_id,
                                        line.order_id.partner_id)
            cur = line.order_id.pricelist_id.currency_id
            res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
        return res

    @api.model
    def _get_checkin_date(self):
        if self._context.get('tz'):
            to_zone = self._context.get('tz')
        else:
            to_zone = 'UTC'
        return _offset_format_timestamp1(time.strftime("%Y-%m-%d 12:00:00"),
                                         '%Y-%m-%d %H:%M:%S',
                                         '%Y-%m-%d %H:%M:%S',
                                         ignore_unparsable_time=True,
                                         context={'tz': to_zone})

    @api.model
    def _get_checkout_date(self):
        if self._context.get('tz'):
            to_zone = self._context.get('tz')
        else:
            to_zone = 'UTC'
        tm_delta = datetime.timedelta(days=1)
        return datetime.datetime.strptime(
            _offset_format_timestamp1(time.strftime("%Y-%m-%d 12:00:00"),
                                      '%Y-%m-%d %H:%M:%S',
                                      '%Y-%m-%d %H:%M:%S',
                                      ignore_unparsable_time=True,
                                      context={'tz': to_zone}),
            '%Y-%m-%d %H:%M:%S') + tm_delta

    @api.onchange('checkout_date', 'checkin_date')
    def onchange_dates(self):
        '''
        This mathod gives the duration between check in and checkout
        if customer will leave only for some hour it would be considers
        as a whole day.If customer will check in checkout for more or equal
        hours, which configured in company as additional hours than it would
        be consider as full days
        --------------------------------------------------------------------
        @param self: object pointer
        @return: Duration and checkout_date
        '''
        company_obj = self.env['res.company']
        configured_addition_hours = 0
        company_ids = company_obj.search([])
        #         if company_ids.ids:
        #             configured_addition_hours = company_ids[0].additional_hours
        myduration = 0
        chckin = self.checkin_date
        chckout = self.checkout_date
        if chckin and chckout:
            server_dt = DEFAULT_SERVER_DATETIME_FORMAT
            chkin_dt = datetime.datetime.strptime(chckin, server_dt)
            chkout_dt = datetime.datetime.strptime(chckout, server_dt)
            dur = chkout_dt - chkin_dt
            sec_dur = dur.seconds
            if (not dur.days and not sec_dur) or (dur.days and not sec_dur):
                myduration = dur.days
            else:
                myduration = dur.days + 1


#             if configured_addition_hours > 0:
#                 additional_hours = abs((dur.seconds / 60) / 60)
#                 if additional_hours >= configured_addition_hours:
#                     myduration += 1
        self.duration = myduration

    checkin_date = fields.Datetime('Check In', default=_get_checkin_date)
    checkout_date = fields.Datetime('Check Out', default=_get_checkout_date)
    checkin = fields.Date('Check In')
    checkout = fields.Date('Check Out')
    is_discount = fields.Boolean('Is Disc')
    duration = fields.Float('Duration in Days',
                            help="Number of days which will automatically "
                            "count from the check-in and check-out date. ")
    partner_discount = fields.Selection([(0, '0'), (10, '10')],
                                        related='order_id.partner_discount',
                                        string='Disc Cust. (%)')
    #partner_discount = fields.Float('Disc Cust. (%)', related='order_id.partner_discount', readonly=True, digits= dp.get_precision('Discount'))
    type = fields.Selection([('adult', 'Adult'), ('child', 'Child')],
                            string='Adult/Child',
                            default='adult')

    def _prepare_order_line_invoice_line(self,
                                         cr,
                                         uid,
                                         line,
                                         account_id=False,
                                         context=None):
        """Save the layout when converting to an invoice line."""
        invoice_vals = super(SaleOrderLine,
                             self)._prepare_order_line_invoice_line(
                                 cr,
                                 uid,
                                 line,
                                 account_id=account_id,
                                 context=context)
        if line.type:
            invoice_vals['type'] = line.type
            invoice_vals['duration'] = line.duration or 1.0
            invoice_vals['is_discount'] = line.is_discount or False
            invoice_vals['checkin'] = line.checkin or False
            invoice_vals['checkout'] = line.checkout or False
        return invoice_vals
class JasperReportCDReceivableFollowUp(models.TransientModel):
    _name = 'jasper.report.cd.receivable.follow.up'
    _inherit = 'report.account.common'

    fiscalyear_start_id = fields.Many2one(default=False, )
    fiscalyear_end_id = fields.Many2one(default=False, )
    filter = fields.Selection(
        readonly=True,
        default='filter_date',
    )
    date_report = fields.Date(
        string='Report Date',
        required=True,
        default=lambda self: fields.Date.context_today(self),
    )
    bank_id = fields.Many2one(
        'res.bank',
        string='Bank',
    )
    bank_branch_id = fields.Many2one('res.bank.branch', string='Bank Branch')
    partner_ids = fields.Many2many(
        'res.partner',
        string='Customers',
        domain="[('customer', '=', True)]",
    )

    @api.onchange('bank_id')
    def _onchange_bank_id(self):
        self.bank_branch_id = False
        self.partner_ids = False

    @api.multi
    def _get_report_name(self):
        self.ensure_one()
        report_name = "cd_receivable_follow_up_group_by_customer"
        if len(self.bank_id):
            report_name = "cd_receivable_follow_up_group_by_bank"
        return report_name

    @api.multi
    def _get_domain(self):
        self.ensure_one()
        dom = [('invoice_plan_id.ref_invoice_id.date_due', '<',
                self.date_report)]
        if self.partner_ids:
            dom += [('loan_agreement_id.borrower_partner_id', 'in',
                     self.partner_ids.ids)]
        if self.bank_id:
            dom += [('loan_agreement_id.bank_id.bank', '=', self.bank_id.id)]
        if self.bank_branch_id:
            dom += [('loan_agreement_id.bank_id.bank_branch', '=',
                     self.bank_branch_id.id)]
        # Check for history view
        dom += [('loan_agreement_id.supplier_invoice_id.date_paid', '!=',
                 False),
                ('loan_agreement_id.supplier_invoice_id.date_paid', '<=',
                 self.date_report), '|',
                ('invoice_plan_id.ref_invoice_id.date_paid', '=', False),
                ('invoice_plan_id.ref_invoice_id.date_paid', '>',
                 self.date_report), '|',
                ('invoice_plan_id.ref_invoice_id.cancel_move_id', '=', False),
                ('invoice_plan_id.ref_invoice_id.cancel_move_id.create_date',
                 '>', self.date_report)]
        return dom

    @api.multi
    def _get_datas(self):
        self.ensure_one()
        data = {'parameters': {}}
        dom = self._get_domain()
        data['ids'] = self.env['cd.receivable.follow.up.view'].search(dom).ids
        date_report = datetime.strptime(self.date_report, '%Y-%m-%d')
        data['parameters']['date_report'] = date_report.strftime('%d/%m/%Y')
        user = self.env.user.with_context(lang="th_TH").display_name
        data['parameters']['user'] = user
        data['parameters']['date_run'] = time.strftime('%d/%m/%Y')
        return data

    @api.multi
    def run_report(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.report.xml',
            'report_name': self._get_report_name(),
            'datas': self._get_datas(),
        }
Exemple #12
0
class hr_timesheet_report(models.Model):
    _name = "hr.timesheet.report"
    _description = "Timesheet"
    _auto = False
    _rec_name = "date"

    date = fields.Date('Date', readonly=True)
    product_id = fields.Many2one('product.product', 'Product', readonly=True)
    user_id = fields.Many2one('res.users', 'User', readonly=True)
    account_id = fields.Many2one('account.analytic.account',
                                 'Analytic Account',
                                 readonly=True)
    company_id = fields.Many2one('res.company', 'Company', readonly=True)
    cost = fields.Float('Cost',
                        readonly=True,
                        digits_compute=dp.get_precision('Account'))
    quantity = fields.Float('Time', readonly=True)

    def _select(self):
        select_str = """
             SELECT min(aal.id) as id,
                    aal.date as date,
                    sum(aal.amount) as cost,
                    sum(aal.unit_amount) as quantity,
                    aal.account_id as account_id,
                    aal.product_id as product_id,
                    aal.user_id as user_id,
                    aal.company_id as company_id,
                    aal.currency_id as currency_id
        """
        return select_str

    def _from(self):
        from_str = """
            FROM account_analytic_line as aal
        """
        return from_str

    def _group_by(self):
        group_by_str = """
            GROUP BY aal.date,
                    aal.account_id,
                    aal.product_id,
                    aal.user_id,
                    aal.company_id,
                    aal.currency_id
        """
        return group_by_str

    def _where(self):
        where_str = """
            WHERE aal.is_timesheet IS TRUE
        """
        return where_str

    def init(self, cr):
        # self._table = hr_timesheet_report
        tools.drop_view_if_exists(cr, self._table)
        cr.execute("""CREATE or REPLACE VIEW %s as (
            %s
            %s
            %s
            %s
            )""" % (self._table, self._select(), self._from(), self._where(),
                    self._group_by()))
Exemple #13
0
class wh_move(models.Model):
    _name = 'wh.move'

    MOVE_STATE = [
        ('draft', u'草稿'),
        ('done', u'已审核'),
    ]

    @api.model
    def _get_default_warehouse(self):
        '''获取调出仓库'''
        if self.env.context.get('warehouse_type'):
            return self.env['warehouse'].get_warehouse_by_type(
                self.env.context.get('warehouse_type'))

        return self.env['warehouse'].browse()

    @api.model
    def _get_default_warehouse_dest(self):
        '''获取调入仓库'''
        if self.env.context.get('warehouse_dest_type'):
            return self.env['warehouse'].get_warehouse_by_type(
                self.env.context.get('warehouse_dest_type'))

        return self.env['warehouse'].browse()

    origin = fields.Char(u'源单类型', required=True)
    name = fields.Char(u'单据编号', copy=False, default='/')
    state = fields.Selection(MOVE_STATE, u'状态', copy=False, default='draft')
    partner_id = fields.Many2one('partner', u'业务伙伴', ondelete='restrict')
    date = fields.Date(u'单据日期',
                       required=True,
                       copy=False,
                       default=fields.Date.context_today)
    warehouse_id = fields.Many2one('warehouse',
                                   u'调出仓库',
                                   ondelete='restrict',
                                   default=_get_default_warehouse)
    warehouse_dest_id = fields.Many2one('warehouse',
                                        u'调入仓库',
                                        ondelete='restrict',
                                        default=_get_default_warehouse_dest)
    approve_uid = fields.Many2one('res.users',
                                  u'审核人',
                                  copy=False,
                                  ondelete='restrict')
    approve_date = fields.Datetime(u'审核日期', copy=False)
    line_out_ids = fields.One2many('wh.move.line',
                                   'move_id',
                                   u'明细',
                                   domain=[('type', '=', 'out')],
                                   context={'type': 'out'},
                                   copy=True)
    line_in_ids = fields.One2many('wh.move.line',
                                  'move_id',
                                  u'明细',
                                  domain=[('type', '=', 'in')],
                                  context={'type': 'in'},
                                  copy=True)
    note = fields.Text(u'备注')

    @api.model
    def scan_barcode(self, model_name, barcode, order_id):
        val = {}
        create_line = False
        att = self.env['attribute'].search([('ean', '=', barcode)])
        if not att:
            raise osv.except_osv(u'错误', u'该产品不存在')
        else:
            if model_name in ['wh.out', 'wh.in']:
                move = self.env[model_name].browse(order_id).move_id
            if model_name == 'wh.out':
                val['type'] = 'out'
                for line in move.line_out_ids:
                    if line.attribute_id.id == att.id:
                        line.goods_qty += 1
                        create_line = True
            if model_name == 'wh.in':
                val['type'] = 'in'
                for line in move.line_in_ids:
                    if line.attribute_id.id == att.id:
                        line.goods_qty += 1
                        create_line = True
            #销售出入库单的二维码
            if model_name == 'sell.delivery':
                move = self.env[model_name].browse(order_id).sell_move_id
                if self.env[model_name].browse(order_id).is_return == True:
                    val['type'] = 'in'
                    for line in move.line_in_ids:
                        if line.attribute_id.id == att.id:
                            line.goods_qty += 1
                            create_line = True
                else:
                    val['type'] = 'out'
                    for line in move.line_out_ids:
                        if line.attribute_id.id == att.id:
                            line.goods_qty += 1
                            create_line = True
            #采购出入库单的二维码
            if model_name == 'buy.receipt':
                move = self.env[model_name].browse(order_id).buy_move_id
                if self.env[model_name].browse(order_id).is_return == True:
                    val['type'] = 'out'
                    for line in move.line_out_ids:
                        if line.attribute_id.id == att.id:
                            line.goods_qty += 1
                            create_line = True
                else:
                    val['type'] = 'in'
                    for line in move.line_in_ids:
                        if line.attribute_id.id == att.id:
                            line.goods_qty += 1
                            create_line = True
            val.update({
                'goods_id': att.goods_id.id,
                'uom_id': att.goods_id.uom_id.id,
                'attribute_id': att.id,
                'goods_qty': 1,
                'move_id': move.id
            })
            if create_line == False:
                self.env['wh.move.line'].create(val)

    @api.multi
    def unlink(self):
        for move in self:
            if move.state == 'done':
                raise osv.except_osv(u'错误', u'不可以删除已经完成的单据')

        return super(wh_move, self).unlink()

    def prev_approve_order(self):
        for order in self:
            if not order.line_out_ids and not order.line_in_ids:
                raise osv.except_osv(u'错误', u'单据的明细行不可以为空')

    @api.multi
    def approve_order(self):
        for order in self:
            order.prev_approve_order()
            order.line_out_ids.action_done()
            order.line_in_ids.action_done()

        return self.write({
            'approve_uid': self.env.uid,
            'approve_date': fields.Datetime.now(self),
            'state': 'done',
        })

    def prev_cancel_approved_order(self):
        pass

    @api.multi
    def cancel_approved_order(self):
        for order in self:
            order.prev_cancel_approved_order()
            order.line_out_ids.action_cancel()
            order.line_in_ids.action_cancel()

        return self.write({
            'approve_uid': False,
            'approve_date': False,
            'state': 'draft',
        })
Exemple #14
0
class OpBookQueue(models.Model):
    _name = 'op.book.queue'
    _inherit = 'mail.thread'
    _rec_name = 'user_id'
    _description = 'Book Queue Request'

    name = fields.Char("Sequence No", readonly=True, copy=False, default='/')
    partner_id = fields.Many2one('res.partner', 'Student/Faculty')
    book_id = fields.Many2one(
        'op.book', 'Book', required=True, track_visibility='onchange')
    date_from = fields.Date(
        'From Date', required=True, default=fields.Date.today())
    date_to = fields.Date('To Date', required=True)
    user_id = fields.Many2one(
        'res.users', 'User', readonly=True, default=lambda self: self.env.uid)
    state = fields.Selection(
        [('request', 'Request'), ('accept', 'Accepted'),
         ('reject', 'Rejected')],
        'Status', copy=False, default='request', track_visibility='onchange')
    student_id = fields.Many2one('op.student', 'Student',readonly=True, default=lambda self: self.env[
            'op.student'].search([('user_default', '=', self.env.uid)]))
    faculty_id = fields.Many2one('op.faculty', 'Faculty')
    library_card_id = fields.Many2one('op.library.card', 'Library Card',track_visibility='onchange')
    # book_unit_id = fields.Many2one('op.book.unit', 'Book Unit',track_visibility='onchange')
    
    @api.multi
    def issue_this_book(self):
        res = { 'name' : 'BookIssueForm',
                'view_type' : 'form',
                'view_mode' : 'form,tree',
                'res_model' : 'op.book.movement',
                'type' : 'ir.actions.act_window',
                }
        return res

    @api.onchange('student_id')
    def onchange_student(self):
        self.library_card_id = self.student_id.library_card_id

    @api.onchange('user_id')
    def onchange_user(self):
        self.partner_id = self.user_id.partner_id.id

    @api.constrains('date_from', 'date_to')
    def _check_date(self):
        if self.date_from > self.date_to:
            raise ValidationError(_('To Date cannot be set before From Date.'))

    @api.model
    def create(self, vals):
        if vals.get('name', '/') == '/':
            vals['name'] = self.env['ir.sequence'].next_by_code(
                'op.book.queue') or '/'
        return super(OpBookQueue, self).create(vals)

    @api.one
    def do_reject(self):
        self.state = 'reject'

    @api.one
    def do_accept(self):
        self.state = 'accept'

    @api.one
    def do_request_again(self):
        self.state = 'request'
class maintenance_intervention(models.Model):
    _name = 'maintenance.intervention'

    _inherit = ['mail.thread', 'ir.needaction_mixin']

    @api.multi
    def print_intervention(self):
        '''
        This function prints the maintenance intervention
        '''
        assert len(
            self
        ) == 1, 'This option should only be used for a single id at a time'

        return self.env['report'].get_action(
            self, 'maintenance.report_maintenance_intervention')

    @api.model
    def _needaction_domain_get(self):
        return [
            '&', ('tasks.user_id', '=', self.env.uid),
            ('state', '=', 'confirmed')
        ]

    @api.one
    def copy(self, default=None):
        new_id = super(maintenance_intervention, self).copy(default)
        new_code = self.env['ir.sequence'].get('maintenance.intervention')
        new_id.code = new_code
        return new_id

    def name_get(self, cr, uid, ids, context=None):
        if not ids:
            return []
        result = []
        for me in self.browse(cr, uid, ids, context=context):
            if me.name:
                result.append((me.id, me.code + ' - ' + me.name))
            else:
                result.append((me.id, me.code))
        return result

    '''
    def _get_intervention_from_task(self):
        return [task.intervention_id.id for task in self.env['maintenance.intervention.task'].browse(cr, uid, ids, context)]
    
    '''

    @api.one
    @api.depends('tasks.user_id', 'date_start', 'to_plan', 'date_end')
    def _get_task_fields(self):
        result = {}

        for intervention in self:
            tech = ""
            to_plan = False
            planned = False
            date_end = None
            date_start = None
            result[intervention.id] = {}

            if intervention.tasks:
                planned = True

            total_hours = 0.

            for task in intervention.tasks:
                if task.planned_hours:
                    total_hours = total_hours + task.planned_hours

                if task.user_id and task.user_id.name not in tech:
                    tech += task.user_id.name + ", "
                if not to_plan:
                    to_plan = task.to_plan
                if planned and not task.date_start or not task.user_id:
                    planned = False

                if (date_start == None and task.date_start) or (
                        task.date_start and task.date_start < date_start):
                    date_start = task.date_start

                if (date_end == None
                        and task.date_end) or (task.date_end
                                               and task.date_end > date_end):
                    date_end = task.date_end

            if intervention.tasks:
                task = intervention.tasks[0]

            intervention.task_hours = total_hours

            if date_start:
                try:
                    intervention.task_month = int(
                        datetime.strptime(date_start,
                                          '%Y-%m-%d %H:%M:%S').strftime('%m'))
                except:
                    intervention.task_month = 0
            else:
                intervention.task_month = 0

            intervention.technicians = tech[0:len(tech) - 2]

            intervention.date_start = date_start

            intervention.date_end = date_end

            intervention.to_plan = False

            if not planned and to_plan and intervention.state != 'done':
                intervention.to_plan = True
            else:
                intervention.to_plan = False

            if planned:
                intervention.task_state = 'planned'
            else:
                intervention.task_state = 'to_plan'

    @api.multi
    def _get_code(self):
        return self.env['ir.sequence'].get('maintenance.intervention')

    code = fields.Char("Code",
                       size=255,
                       index=True,
                       required=True,
                       default=_get_code)
    name = fields.Text("Description", index=True)
    partner_id = fields.Many2one("res.partner",
                                 type="many2one",
                                 related='installation_id.partner_id',
                                 readonly=True,
                                 string="Customer",
                                 store=True,
                                 help="Customer linked to the installation")
    address_id = fields.Many2one("res.partner",
                                 related="installation_id.address_id",
                                 readonly=True,
                                 string="Address",
                                 store=True,
                                 help="Address of the installation")
    installation_id = fields.Many2one('maintenance.installation',
                                      string='Installation',
                                      required=True)
    state = fields.Selection([('cancel', 'Cancel'), ('draft', 'Draft'),
                              ('confirmed', 'Confirmed'), ('done', 'Done')],
                             string="Intervention State",
                             readonly=True,
                             default='draft',
                             track_visibility='onchange')
    task_state = fields.Selection(compute='_get_task_fields',
                                  size=255,
                                  default='to_plan',
                                  readonly=True,
                                  string="Task state",
                                  selection=[('to_plan', 'To plan'),
                                             ('planned', 'Planned')])
    tasks = fields.One2many('maintenance.intervention.task', 'intervention_id',
                            'Tasks')
    int_comment = fields.Text("Internal comment")
    ext_comment = fields.Text("External comment")
    maint_type = fields.Many2one('maintenance.intervention.type',
                                 string='Type',
                                 required=True)
    contact_address_id = fields.Many2one('res.partner', string='Contact')
    contact_phone = fields.Char(relation="res.partner",
                                related="contact_address_id.phone",
                                string="Contact phone")
    technicians = fields.Char(compute='_get_task_fields',
                              size=255,
                              string="Technician",
                              store=True)
    to_plan = fields.Boolean(compute='_get_task_fields',
                             string="To plan",
                             store=True)
    date_scheduled = fields.Date('Scheduled date')
    date_start = fields.Datetime(compute='_get_task_fields',
                                 string="Beginning",
                                 store=True)
    date_end = fields.Datetime(compute='_get_task_fields',
                               string="End",
                               store=True)
    task_hours = fields.Float(compute='_get_task_fields',
                              size=255,
                              string="Task hours",
                              store=True)
    task_month = fields.Integer(compute='_get_task_fields',
                                size=255,
                                string="Task month",
                                store=True)
    time_planned = fields.Float(
        'Time planned', help='Time initially planned to do intervention.')

    _order = 'id desc'

    @api.onchange('installation_id')
    def on_change_installation_id(self):
        if self.installation_id:
            self.partner_id = self.installation_id.id
            self.contact_address_id = self.installation_id.contact_address_id.id

    @api.one
    def action_cancel(self):
        self.state = 'cancel'

    @api.one
    def action_done(self):
        self.state = 'done'

    @api.one
    def action_confirm(self):
        self.state = 'confirmed'
Exemple #16
0
class HrHolidays(models.Model):
    _inherit = "hr.holidays"

    # TODO
    # To be removed after fixing
    # https://github.com/odoo/odoo/issues/2605
    def init(self, cr):
        cr.execute("""
        ALTER TABLE hr_holidays ALTER COLUMN holiday_status_id DROP NOT NULL;
        ALTER TABLE hr_holidays DROP CONSTRAINT hr_holidays_type_value;
        ALTER table hr_holidays
                  ADD constraint hr_holidays_type_value
                  CHECK((holiday_type='employees')
                  or (holiday_type='employee' AND employee_id IS NOT NULL)
                  or (holiday_type='category' AND category_id IS NOT NULL));
                """)

    @api.multi
    def _check_date(self):
        """
        Override function
        - Remove all source code in this function
            because now all processes base on leave lines
            instead of leave request
        - Move this control into leave lines
        """
        return True

    @api.multi
    def _get_can_reset(self):
        """
        Override function
        User can reset a leave request
            if it is its own leave request or if he is an HR Officer.
        """
        user = self.env.user

        for holiday in self:
            if user.has_group('base.group_hr_user'):
                holiday.can_reset = True
            elif holiday.employee_id and holiday.employee_id.user_id and\
                            holiday.employee_id.user_id.id == user.id:
                holiday.can_reset = True

    can_reset = fields.Boolean(compute=_get_can_reset, string='Can Reset')

    # Change size of field name
    name = fields.Char(string='Description', size=255)

    # Change date_from, date_to from datetime to date
    date_from = fields.Date()
    date_to = fields.Date()

    # Set Leave Type is not required
    holiday_status_id = fields.Many2one(required=False)

    # New fields
    is_unpaid = fields.Boolean("Filter Unpaid")
    allo_date = fields.Date(readonly=1)
    month_year = fields.Char(string='Period', readonly=1)
    holiday_line = fields.One2many('hr.holidays.line',
                                   'holiday_id',
                                   readonly=True,
                                   states={
                                       'draft': [('readonly', False)],
                                       'confirm': [('readonly', False)]
                                   })
    is_over_allocation_days = fields.Boolean(
        default=False,
        help='The balance of allowed holidays is negative, \
        it is a request for advance leaves')
    employee_ids = fields.Many2many('hr.employee',
                                    'hr_holiday_employee_rel',
                                    'holiday_id',
                                    'employee_id',
                                    string="Employees",
                                    readonly=True,
                                    states={
                                        'draft': [('readonly', False)],
                                        'confirm': [('readonly', False)]
                                    })

    _constraints = [
        # Override to remove this constraint
        (_check_date, 'You can not have 2 leaves that overlaps on same day!',
         ['date_from', 'date_to']),
    ]

    _sql_constraints = [
        # Override to change this constraints base on employees holiday_type
        ('type_value', """CHECK((holiday_type='employees')
         or (holiday_type='employee' AND employee_id IS NOT NULL)
         or (holiday_type='category' AND category_id IS NOT NULL))""",
         """The employee or employee category of this request is missing.
         Please make sure that your user login is linked to an employee."""),
    ]

    @api.onchange('holiday_type')
    def _onchange_type(self):
        """
        @param holiday_type: employee/employees
        @return:
            - If holiday type is employees, set employee_id = False
            - If holiday type is employee, set employee_ids = []
        """
        emp_obj = self.env['hr.employee']
        if self.holiday_type == 'employee':
            employees = emp_obj.search([('user_id', '=', self._uid)])
            self.employee_ids = []
            self.category_id = False
            self.employee_id = employees and employees[0].id
        elif self.holiday_type == 'employees':
            self.employee_id = False
            self.category_id = False
        else:
            self.employee_ids = []
            self.employee_id = False

    @api.multi
    def check_holidays(self):
        """
        For each leave request line, check the remaining leaves enough or not
        If balance < 0, update is_over_allocation_days and show
            the warning on leave request from
        """

        is_over_allocation_days = False
        for record in self:
            if record.type == 'add':
                continue

            # Check leaves balance for leave requests
            # leaves_rest: remaining_leaves of employee by leave type
            # leave_asked: number_of_days of holiday_line
            if record.holiday_type == 'employee'\
               and record.employee_id:
                for i in record.holiday_line:
                    leave_asked = -(i.number_of_days)
                    if leave_asked < 0.00:
                        if i.holiday_status_id \
                           and not i.holiday_status_id.limit:
                            status_id = i.holiday_status_id.id
                            employee_id = record.employee_id.id
                            status = i.holiday_status_id.get_days(employee_id)
                            leaves_rest = status[status_id]['remaining_leaves']
                            if (record.state == 'validate' and
                                leaves_rest < 0) or \
                                    (record.state != 'validate' and
                                     leaves_rest < -(leave_asked)):
                                # 1. For approved leave request,
                                # the number of days on holiday lines
                                # is taken into the remaining leaves.
                                # if remaining leaves < 0, means balance < 0
                                # 2. For leave request not approved
                                # the remaining leaves must be greater than
                                # number of days on leave request line,
                                # means balance < 0
                                is_over_allocation_days = True
            elif record.holiday_type == 'category' and record.category_id:
                for i in record.holiday_line:
                    leave_asked = -(i.number_of_days)
                    if leave_asked < 0.00:
                        if not i.holiday_status_id.limit:
                            cate_id = record.category_id.id
                            status_id = i.holiday_status_id.id
                            status = i.holiday_status_id.get_days(cate_id)
                            leaves_rest = status['remaining_leaves']
                            if leaves_rest < -(leave_asked):
                                is_over_allocation_days = True
            record.write({'is_over_allocation_days': is_over_allocation_days})
        return True

    @api.multi
    def holidays_validate(self):
        """
        Override function:
        - When approve the allocation request
            update is_over_allocation_days = False if remmaining_leaves >= 0
        """
        emp_obj = self.env['hr.employee']
        line_obj = self.env['hr.holidays.line']
        status_obj = self.env['hr.holidays.status']

        manager = emp_obj.search([('user_id', '=', self._uid)], limit=1)
        manager = manager and manager.id or False
        val_update = {}
        for record in self:
            if record.state == 'cancel_request':
                # Leave request with status `cancel_request`
                # Only need to update status to `validate`
                continue
            if record.double_validation:
                val_update.update({'manager_id2': manager})
            else:
                val_update.update({'manager_id': manager})

            if record.type == 'add':
                # UPDATE is_over_allocation_days = False
                #     if remmaining_leaves >= 0
                # When approve allocation requests
                leaves_rest = status_obj.get_days(record.employee_id.id)
                status_id = record.holiday_status_id.id
                leaves_rest = leaves_rest\
                    and leaves_rest[status_id]['remaining_leaves'] or 0
                if leaves_rest >= 0:
                    domain = [('is_over_allocation_days', '=', True),
                              ('type', '=', 'remove'),
                              ('employee_id', '=', record.employee_id.id)]
                    leaves = self.search(domain)
                    leaves.check_holidays()

            if record.holiday_type == 'employee' and record.type == 'remove':
                # Create calendar event base leave request lines
                for line in record.holiday_line:
                    meeting_obj = self.env['calendar.event']
                    categ_ids = line.holiday_status_id.categ_id\
                        and [(6, 0, [record.holiday_status_id.categ_id.id])]\
                        or []
                    start_date = datetime.strptime(line.first_date, DF)
                    stop_date = datetime.strptime(line.last_date, DF)
                    meeting_vals = {
                        'name': record.name or _('Leave Request'),
                        'categ_ids': categ_ids,
                        'duration': line.number_of_days * 8,
                        'description': record.notes,
                        'user_id': record.user_id.id,
                        'start': start_date.strftime("%Y-%m-%d 00:00:00"),
                        'stop': stop_date.strftime("%Y-%m-%d 00:00:00"),
                        'allday': False,
                        'state': 'open',  # block this date in the calendar
                        'class': 'confidential'
                    }
                    # Add the partner_id (if exist) as an attendee
                    if record.user_id and record.user_id.partner_id:
                        partner_ids = [(4, record.user_id.partner_id.id)]
                        meeting_vals['partner_ids'] = partner_ids

                    context = dict(self._context)
                    context.update({'no_email': True})
                    meeting = meeting_obj.with_context(context).create(
                        meeting_vals)
                    self._create_resource_leave([record])
                    val_update.update({'meeting_id': meeting.id})

            elif record.holiday_type in ('category', 'employees'):
                if record.holiday_type == 'category':
                    domain = [('category_ids', 'child_of',
                               [record.category_id.id])]
                    emp_ids = emp_obj.search(domain)
                else:
                    emp_ids = [employee.id for employee in record.employee_ids]
                if not emp_ids:
                    continue

                leaves = []
                for employee_id in emp_ids:
                    total_days = 0.0
                    # create leave request for each employee
                    leave = self.create({
                        'name': record.name,
                        'holiday_type': 'employee',
                        'employee_id': employee_id,
                        'number_of_days_temp': record.number_of_days_temp,
                        'date_from': record.date_from,
                        'date_to': record.date_to
                    })
                    leaves.append(leave)

                    # create leave request lines
                    for line in record.holiday_line:
                        total_days += line.number_of_days
                        line_obj.create({
                            'holiday_id':
                            leave.id,
                            'holiday_status_id':
                            line.holiday_status_id.id,
                            'first_date':
                            line.first_date,
                            'last_date':
                            line.last_date,
                            'first_date_type':
                            line.first_date_type,
                            'last_date_type':
                            line.last_date_type,
                            'number_of_days':
                            line.number_of_days,
                        })

                    # update number of date in leave request
                    leave.write({'number_of_days_temp': total_days})

                # Approve all leave request created from
                #     leave request of many employees
                for leave in leaves:
                    for sig in ('confirm', 'validate', 'second_validate'):
                        leave.signal_workflow(sig)
        val_update.update({'state': 'validate'})
        self.write(val_update)
        return True

    @api.multi
    def change_state_to_cancel(self):
        """
        Manager accepts the Cancellation Request from employee.
        Then status of this leave request is `cancel`
        """
        self.write({'state': 'cancel'})
        for record in self:
            # Delete the meeting
            if record.meeting_id:
                record.meeting_id.unlink()
            record.signal_workflow('accept_cancellation')
        self._remove_resource_leave()
        return True

    @api.model
    def create_allo_request(self,
                            employee_id,
                            days,
                            leave_type=False,
                            allo_date=False,
                            update_extra_leave=False,
                            name=_('Allocation request for every month')):
        """
        Create allocation request every month for an employee
        If existed, update name and allocation days.
        @param name: default "Allocation Request for every month"
        @param leave_type: default "Casual Leave"
        @param employee_id: Employee ID
        @param days: monthly_paid_leave + extra leaves (if any) on contract
        @param allo_date: date create allocation request
        @return: New validated allocation request
        """
        allocation = False
        status_obj = self.env['hr.holidays.status']
        param_obj = self.env['ir.config_parameter']
        if not leave_type:
            # If there have no an indicated leave type
            # Find the leave type defined in the parameter
            # default_leave_type_to_add_allocation_each_month
            status_name = 'default_leave_type_to_add_allocation_each_month'
            status_name = param_obj.get_param(status_name)
            leave_type = status_obj.search([('name', '=', status_name)])
            if not leave_type:
                return allocation

        # Find the allocation request of the indicated employee in this month
        if not allo_date:
            allo_date = date.today()
        domain = [
            ('employee_id', '=', employee_id),
            ('type', '=', 'add'),
            ('holiday_status_id', '=', leave_type.id),
            ('month_year', '=', allo_date.strftime('%m/%Y')),
            ('number_of_days_temp', '=', days),
        ]
        allocation = self.search(domain)
        if allocation:
            # Do nothing or update if needed
            allocation = allocation[0]
            logging.info(
                '=== Allocation request was already existed (ID: %s)' %
                (allocation.id))
            if update_extra_leave and days > 0:
                # update number_of_days of AR if:
                # - update_extra_leave = True
                #     + Use in script re-calculate for old data
                #     + Use in re-run scheduler create AR
                #        for specific date, employee
                # - New allocation days > allocation days on this AR
                updated_days = allocation.number_of_days_temp + days
                name += ' - Auto update the duration from %s to %s'\
                    % (allocation.number_of_days_temp, updated_days)
                allocation.write({
                    'name': name,
                    'number_of_days_temp': updated_days
                })
                logging.info('=== UPDATE allocation request (ID: %s, %s, %s)' %
                             (allocation.id, name, updated_days))
        else:
            # Create allocation request
            values = {
                'name': name,
                'holiday_status_id': leave_type.id,
                'holiday_type': 'employee',
                'employee_id': employee_id,
                'number_of_days_temp': days,
                'type': 'add',
                'allo_date': allo_date,
                'month_year': allo_date.strftime('%m/%Y'),
            }
            allocation = self.create(values)
            for sig in ('confirm', 'validate', 'second_validate'):
                allocation.signal_workflow(sig)
            logging.info('=== CREATE allocation request (ID: %s)' %
                         (allocation.id))
        return allocation

    @api.model
    def add_allocation_request_each_month(self,
                                          allo_date=None,
                                          emps=None,
                                          update_extra_leave=False):
        """
        Scheduler function:
        Add allocation request at beginning of every month
        Only Create AR for the employees start working before 15th/M
        @param year_month: indicated period to create AR
            Example: ('2015-01-01', list of employee IDs)
        @param emps: list employee to create AR
        @param update_extra_leave:
            If active, allow to update existed AR,
                days= current number_of_days + extra leaves
            If not, only create new AR if not exist.
        """
        ctx = dict(self._context) or {}
        res = []
        contract_obj = self.env['hr.contract']

        # Only create allocation request in indicated period
        if allo_date:
            allo_date = datetime.strptime(allo_date, DF)
        else:
            allo_date = datetime.today()
        logging.info("======= ALLOCATION DATE: %s======" % allo_date)
        fifteenth_date = allo_date + relativedelta(day=15)
        str_fifteenth_date = fifteenth_date.strftime(DF)
        # Create allocation request for contracts:
        # Official contracts (is_trial is inactive)
        # Start the 15th/Month
        # End after 15th/Month
        domain = [
            ('date_start', '<=', str_fifteenth_date),
            '|',
            ('date_end', '>=', str_fifteenth_date),
            ('date_end', '=', False),
            ('is_trial', '=', False),
            ('employee_id.active', '=', True),
        ]
        if emps:
            # Only create allocation request for the indicated employees
            if isinstance(emps, str):
                emps = eval(emps)
            domain += [('employee_id', 'in', emps)]

        contracts = contract_obj.search(domain)
        for contract in contracts:
            # Create allocation request with
            # allocation days = monthly paid leaves + extra leaves
            allocation_days = contract.monthly_paid_leaves
            employee = contract.employee_id
            logging.info("=== EMPLOYEE %s" % employee.name)
            description = 'Allocation Request for every month'
            job = contract and contract.job_id or False
            if not job:
                logging.warning(
                    "=== There is no job title defined on %s's contract." %
                    employee.name)
            else:
                # Calculate extra leave for Work Seniority
                # Plus to total_extra_leave
                # if work seniority of this employee equal to
                #    factor * work seniority interval (defined on job)
                seniority_config = job.work_seniority_interval * 12
                if not seniority_config:
                    logging.warning(
                        "=== Work Seniority Interval is not set on %s job" %
                        job.name)
                else:
                    # work_seniority_month from hire_date to allo_date
                    ctx.update({'to_date': allo_date})
                    seniority_emp = employee.with_context(ctx).\
                        work_seniority_month
                    logging.info("=== Work Seniority: %s" % seniority_emp)
                    factor = seniority_config > 0 and \
                        seniority_emp / seniority_config or 0
                    if seniority_emp \
                       and seniority_emp == seniority_config * int(factor):
                        extra_leaves = \
                            job.extra_annual_leaves_for_work_seniority * factor
                        allocation_days += extra_leaves
                        description += ' - Plus %s extra leave(s)' \
                            ' for %s year(s) '\
                            % (extra_leaves, seniority_emp / 12) + \
                            'working seniority'
            record = self.create_allo_request(
                employee.id,
                days=allocation_days,
                update_extra_leave=update_extra_leave,
                name=description,
                allo_date=allo_date)
            res.append(record.id)
        return res

    @api.model
    def create(self, vals):
        """ For Leave Request, The number_of_days of
            Leave Request is sum of number_of_days of Leave Request lines
            For Allocation Request, Update these fields:
            - Allocation created date
            - Month/year
        """
        context = self._context
        if context and context.get('default_type', False):
            vals['type'] = context['default_type']

        line_obj = self.env['hr.holidays.line']
        emp_obj = self.env['hr.employee']

        if vals.get('type', False) == 'add':
            # Allocation Request
            month_year = vals.get('month_year', False) \
                or date.today().strftime('%m/%Y')
            vals.update({'allo_date': date.today(), 'month_year': month_year})
            # Create allocation request line to show to leave summary
            holiday_line = {
                'holiday_status_id': vals.get('holiday_status_id', False),
                'number_of_days': vals.get('number_of_days_temp', 0),
                'first_date_type': False,
                'last_date_type': False
            }
            vals.update({'holiday_line': [[0, False, holiday_line]]})
        else:
            # Leave Request
            holiday_lines = vals.get('holiday_line', False)
            if holiday_lines:
                # Get values of first holiday line
                first_line = holiday_lines[0][2]
                first_date = first_line['first_date']
                last_date = first_line['last_date']
                first_date_type = first_line['first_date_type']
                last_date_type = first_line['last_date_type']
                employee = emp_obj.browse(vals['employee_id'])
                days = line_obj._calculate_days(employee, first_date,
                                                last_date, first_date_type,
                                                last_date_type)
                for holiday_line in holiday_lines[1:]:
                    # Fore in each the rest of holiday line
                    line = holiday_line[2]
                    if line:
                        line_first_date = line['first_date']
                        line_last_date = line['last_date']
                        line_first_date_type = line['first_date_type']
                        line_last_date_type = line['last_date_type']
                        days += line_obj._calculate_days(
                            employee, line_first_date, line_last_date,
                            line_first_date_type, line_last_date_type)
                        if line_first_date < first_date:
                            first_date = line_first_date
                        if line_last_date > last_date:
                            last_date = line_last_date
                vals['date_from'] = first_date
                vals['date_to'] = last_date
                vals['number_of_days_temp'] = days
        return super(HrHolidays, self).create(vals)

    @api.multi
    def write(self, vals):
        """
        - Update state of leave request line = state of leave request
        - For Leave Request, The number_of_days of
            Leave Request is sum of number_of_days of Leave Request lines
        """
        line_obj = self.env['hr.holidays.line']
        emp_obj = self.env['hr.employee']
        user_obj = self.env['res.users']

        if vals.get('state') \
                and vals['state'] not in ['draft', 'confirm',
                                          'cancel', 'cancel_request']\
                and not user_obj.has_group('base.group_hr_user'):
            # Add cancel_request in list of status that a normal user
            # can change
            raise Warning(
                _('You cannot set a leave request as'
                  ' \'%s\'. Contact a human resource manager.') %
                vals.get('state'))

        for record in self:
            holiday_lines = record.holiday_line
            holiday_line_vals = {}
            # Update number of days to allocation request line
            if record.type == 'add' and 'number_of_days_temp' in vals:
                holiday_line_vals = {
                    'number_of_days': vals['number_of_days_temp']
                }

            # Update state to holiday lines
            if vals.get('state', False):
                holiday_line_vals.update({'state': vals['state']})

            # Update state to holiday lines
            if vals.get('employee_id', False):
                holiday_line_vals.update({'employee_id': vals['employee_id']})

            if holiday_line_vals:
                # Update vals from holiday to holiday lines
                holiday_lines.write(holiday_line_vals)

            # Calculate number_of_days = sum(number_of_days of holiday lines)
            if vals.get('holiday_line', False):
                # Leave Request
                holiday_lines = vals.get('holiday_line', False)
                employee = record.employee_id
                if vals.get('employee_id'):
                    employee = emp_obj.browse(vals['employee_id'])

                # The first holiday line
                # flag: Get number describe action of each row:
                # 0-new; 4-update and 2-delete.
                # In this case, we want to check "DELETE" case
                flag = holiday_lines[0][0]
                line_id = holiday_lines[0][1]
                line_rec = line_id and line_obj.browse(line_id)
                line_vals = holiday_lines[0][2]
                days = record.number_of_days_temp
                # Get old values of the first holiday
                first_date = line_id and line_rec.first_date or False
                last_date = line_id and line_rec.last_date or False
                first_date_type = line_id and line_rec.first_date_type or False
                last_date_type = line_id and line_rec.last_date_type or False

                if flag == 2:
                    # This line is deleted
                    days -= line_rec.number_of_days
                else:
                    # This is new line or updated line
                    # Calculate number_of_days for the first holiday_line
                    if line_vals:
                        # Get changed values on the first holiday
                        # If not, get the old values
                        first_date = line_vals.get('first_date', first_date)
                        last_date = line_vals.get('last_date', last_date)
                        first_date_type = line_vals.get(
                            'first_date_type', first_date_type)
                        last_date_type = line_vals.get('last_date_type',
                                                       last_date_type)
                        day = line_obj._calculate_days(employee, first_date,
                                                       last_date,
                                                       first_date_type,
                                                       last_date_type)
                        if line_rec:
                            days += day - line_rec.number_of_days
                        else:
                            days += day

                for holiday_line in holiday_lines[1:]:
                    # flag: Get number describe action of each row:
                    # 0-new; 4-update and 2-delete.
                    # In this case, we want to check "DELETE" case
                    flag = holiday_line[0]
                    line_id = holiday_line[1]
                    line_rec = line_id and line_obj.browse(line_id)
                    line_vals = holiday_line[2]

                    # The old values of this holiday_line
                    line_first_date = line_id and line_rec.first_date or False
                    line_last_date = line_id and line_rec.last_date or False
                    line_first_date_type = line_id and \
                        line_rec.first_date_type \
                        or False
                    line_last_date_type = line_id and line_rec.last_date_type \
                        or False

                    if flag == 2:
                        days -= line_rec.number_of_days
                    else:
                        if not line_vals:
                            continue
                        # Get new values of this holiday line
                        line_first_date = line_vals.get(
                            'first_date', line_first_date)
                        line_last_date = line_vals.get('last_date',
                                                       line_last_date)
                        line_first_date_type = line_vals.get(
                            'first_date_type', line_first_date_type)
                        line_last_date_type = line_vals.get(
                            'last_date_type', line_last_date_type)
                        day = line_obj._calculate_days(employee,
                                                       line_first_date,
                                                       line_last_date,
                                                       line_first_date_type,
                                                       line_last_date_type)
                        if line_rec:
                            days += day - line_rec.number_of_days
                        else:
                            days += day

                    # Recalculate date_from = MIN first_date of holiday lines
                    # date_to = MAX last_date of holiday lines
                    if line_first_date < first_date:
                        first_date = line_first_date
                    if line_last_date > last_date:
                        last_date = line_last_date

                vals['date_from'] = first_date
                vals['date_to'] = last_date
                vals['number_of_days_temp'] = days
            super(models.Model, self).write(vals)
        return True

    # TODO: check why the return value of search_count is not correct
    # when overriding search function by using v8 code style.
    def search(self,
               cr,
               uid,
               args,
               offset=0,
               limit=None,
               order=None,
               count=False,
               context={}):
        """ Override function:
        For leave request, the filter by using leave type must be searched on
            the Leave Request line_ids
        """
        hol_line_obj = self.pool['hr.holidays.line']
        hol_status_obj = self.pool['hr.holidays.status']
        # ticket 3,772 - filter Unpaid payment type
        is_unpaid = False
        for arg in args:
            if arg[0] == 'is_unpaid':
                is_unpaid = True
                del args[args.index(arg)]
                break
        if is_unpaid:
            status_rec_ids = hol_status_obj.search(
                cr, uid, [('payment_type', '=', 'unpaid')])
            result = []
            if status_rec_ids:
                line_ids = hol_line_obj.search(
                    cr, uid, [('holiday_status_id', 'in', status_rec_ids)])
                if line_ids:
                    result = []
                    for line in hol_line_obj.browse(cr,
                                                    uid,
                                                    line_ids,
                                                    context=context):
                        if line.holiday_id.id not in result:
                            result.append(line.holiday_id.id)
            args.append(['id', 'in', result])

        # Ticket 2912: The filter by using leave type doesn't work
        # Filter by leave type on leave request line
        # OR leave type on allocation request
        type_value = ''
        for arg in args:
            try:
                if arg.index('type') == 0:
                    type_value = arg[2]
                    break
            except ValueError:
                pass
        if type_value == 'remove':
            value = False
            for arg in args:
                try:
                    if arg.index('holiday_status_id') == 0:
                        value = arg[2]
                        operator = arg[1]
                        del args[args.index(arg)]
                except ValueError:
                    pass
            if value:
                domain = []
                if operator in ('ilike', 'like'):
                    domain.append(('holiday_status_id.name', operator, value))
                else:
                    domain.append(('holiday_status_id', operator, value))
                line_ids = hol_line_obj.search(cr, uid, domain)
                holiday_ids = [
                    x.holiday_id.id for x in hol_line_obj.browse(
                        cr, uid, line_ids, context=context)
                ]
                args.append(['id', 'in', holiday_ids])

        return super(HrHolidays, self).search(cr,
                                              uid,
                                              args,
                                              offset=offset,
                                              limit=limit,
                                              order=order,
                                              count=count)

    @api.model
    def compute_allo_days(self,
                          employee_id,
                          hol_status_ids,
                          date_from=False,
                          date_to=False):
        """
        Calculate the allocation request which was approved
        """
        if not hol_status_ids:
            return 0
        sql = """
        SELECT
            CASE
                WHEN SUM(h.number_of_days) > 0 THEN SUM(h.number_of_days)
                ELSE 0
            END as allo_days
            FROM
                hr_holidays h
                join hr_holidays_status s on (s.id=h.holiday_status_id)
            WHERE
                h.type='add' AND
                h.state='validate' AND
                s.limit=False AND
                h.employee_id = %s AND
                h.holiday_status_id in (%s)
        """ % (
            employee_id,
            ','.join(map(str, hol_status_ids)),
        )
        if date_from and date_to:
            sql += """ AND h.allo_date >= '%s'
                       AND h.time_of_allocation_date <= '%s'
                       """ % (date_from, date_to)
        elif not date_from and date_to:
            sql += " AND h.allo_date <= '%s'" % (date_to)
        elif date_from and not date_to:
            sql += " AND h.allo_date >= '%s'" % (date_from)
        self._cr.execute(sql)
        res = self._cr.fetchone()
        return res and res[0] or 0

    @api.model
    def compute_leave_days(self,
                           employee_id,
                           hol_status_ids,
                           date_from=False,
                           date_to=False):
        """
        Calculate the number of leave days in the indicated period of time
        """

        if not hol_status_ids:
            return 0
        condition = """
            FROM
                hr_holidays h
                join hr_holidays_line hl on (h.id=hl.holiday_id)
            WHERE
                h.type='remove' AND
                h.state='validate' AND
                h.employee_id = %s AND
                hl.holiday_status_id in (%s)
            """ % (employee_id, ','.join(map(str, hol_status_ids)))

        sql = "SELECT sum(hl.number_of_days)" + condition
        other_sql = """SELECT hl.first_date, hl.last_date, hl.first_date_type,
                        hl.last_date_type""" + condition
        cr = self._cr
        line_obj = self.env['hr.holidays.line']
        contract_obj = self.env['hr.contract']

        if date_from and date_to:
            # first date > date from and last date < date to
            sql += """AND hl.last_date < '%s'
                      AND hl.first_date > '%s'""" % (date_to, date_from)
            cr.execute(sql)
            res = cr.fetchone()
            # first date <= date from and last date >= date from
            # OR first date <= date to and last date >= date to
            other_sql += """AND (( hl.first_date <= '%s' AND hl.last_date >= '%s')
                            OR (hl.first_date <= '%s' AND hl.last_date >= '%s')
                            )""" % (date_from, date_from, date_to, date_to)
            cr.execute(other_sql)
            other_res = cr.fetchall()

        elif not date_from and date_to:
            # NOT date from and last date < date to
            sql += "AND hl.last_date < '%s'" % (date_to)
            cr.execute(sql)
            res = cr.fetchone()

            # OR first date <= date to and last date >= date to
            other_sql += """AND (hl.first_date <= '%s'
                            AND hl.last_date >= '%s')""" % (date_to, date_to)
            cr.execute(other_sql)
            other_res = cr.fetchall()

        elif date_from and not date_to:
            # first date > date from and NOT date to
            sql += "AND hl.first_date > '%s'" % (date_from)
            cr.execute(sql)
            res = cr.fetchone()

            # first date <= date from and last date >= date from
            other_sql += """AND ( hl.first_date <= '%s'
                            AND hl.last_date >= '%s')
                            """ % (date_from, date_from)
            cr.execute(other_sql)
            other_res = cr.fetchall()
        else:
            cr.execute(sql)
            res = cr.fetchone()
            return res and res[0] or 0
        """Calculate number of days"""
        number_of_days = res and res[0] or 0
        employee = self.env['hr.employee'].browse(employee_id)

        company = employee.company_id
        country_id = False
        if company and company.country_id:
            country_id = company.country_id.id
        for line in other_res:
            str_start_date = date_from and max(line[0], date_from) or line[0]
            start_date = datetime.strptime(str_start_date, DF).date()
            str_date_end = date_to and min(line[1], date_to) or line[1]
            end_date = datetime.strptime(str_date_end, DF).date()
            # Get the valid contract in (start_date, end_date)
            # Get the latest valid contract
            # Get the working schedule of this contract
            working_hours = False
            contract_obj = self.env['hr.contract']
            contract_ids = contract_obj.get_contract(employee.id, start_date,
                                                     end_date)
            if contract_ids:
                contract = contract_obj.browse(contract_ids[-1])
                if contract.working_hours:
                    working_hours = contract.working_hours.id

            while start_date <= end_date:
                date_type = 'full'
                if start_date == datetime.strptime(line[0], '%Y-%m-%d').date():
                    date_type = line[2]
                if start_date == datetime.strptime(line[1], '%Y-%m-%d').date():
                    date_type = line[3]
                number_of_days += line_obj.plus_day(working_hours, start_date,
                                                    date_type, country_id)
                start_date = start_date + timedelta(1)
        return number_of_days
class maintenance_element(models.Model):
    _name = 'maintenance.element'
    _inherit = ['mail.thread']
    _order = 'name'

    @api.one
    def copy(self, default=None):
        new_element = super(maintenance_element, self).copy(default)
        new_element.code = self.env['ir.sequence'].get('maintenance.element')

    @api.multi
    def name_get(self):
        result = []
        for element in self:
            if element.serial_number:
                result.append(
                    (element.id, element.code + ' - ' + element.name + ' - [' +
                     element.serial_number + ']'))
            else:
                result.append(
                    (element.id, element.code + ' - ' + element.name))
        return result

    #add search on code
    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        res = super(maintenance_element,
                    self).name_search(name, args, operator, limit)
        if res:
            return res
        else:
            if not args:
                args = []
            args.append(('code', operator, name))
            elements = self.search(args, limit=limit)
            result = elements.name_get()
        return result

    @api.multi
    def _get_code(self):
        return self.env['ir.sequence'].get('maintenance.element')

    installation_id = fields.Many2one('maintenance.installation',
                                      'Installation',
                                      index=True)
    code = fields.Char("Code", size=255, index=True, default=_get_code)
    partner_id = fields.Many2one(related="installation_id.partner_id",
                                 relation="res.partner",
                                 readonly=True,
                                 string="Customer",
                                 store=True)
    name = fields.Char("Name", size=255, index=True)
    product_id = fields.Many2one('product.product', 'Product', index=True)
    serial_number = fields.Char("Serial Number", size=255, index=True)
    description = fields.Text("Description")
    installation_date = fields.Date("Installation date")
    warranty_date = fields.Date("Warranty date")
    location = fields.Char("Location", size=255)
    #TODO:A METTRE DANS ELNEO_MAINTENANCE
    #'suivi_tmi':fields.text("Suivi TMI"),
    #'piece_tmi':fields.text("Piece TMI", readonly=True),
    address_id = fields.Many2one(related="installation_id.address_id",
                                 relation="res.partner",
                                 readonly=True,
                                 string="Installation Address")
    serialnumber_required = fields.Boolean("Serial number required")
    visible_for_intervention = fields.Boolean("Visible for interventions",
                                              default=True)
    active = fields.Boolean("Active", default=True)
    warehouse_id = fields.Many2one(related='installation_id.warehouse_id',
                                   relation='sale.shop',
                                   string="Warehouse")
class grpCajaChicaAccountVoucherWizard(models.TransientModel):
    _name = "grp.caja.chica.account.voucher.wizard"

    @api.model
    def fields_view_get(self, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
        res = super(grpCajaChicaAccountVoucherWizard, self).fields_view_get(view_id=view_id, view_type=view_type,
                                                                            context=context,
                                                                            toolbar=toolbar, submenu=submenu)
        doc = etree.XML(res['arch'])
        if self._context is not None and 'default_caja_chica_id' in self._context:
            caja_id = self._context['default_caja_chica_id']
            caja = self.env['grp.caja.chica.tesoreria'].search([('id', '=', caja_id)])
            account_vouchers = self.env['account.voucher'].search([('state', '=', 'confirm'),
                                                                   ('id', 'not in',
                                                                    caja.transaction_ids.mapped('voucher_id').ids),
                                                                   ('journal_id.caja_chica_t', '=', True),
                                                                   ('journal_id.operating_unit_id', 'in',
                                                                    caja.box_id.operating_unit_ids.ids)
                                                                   ])
            if self.env.user.company_id.box_refund_in_selection == 'out_box':
                account_vouchers += self.env['account.voucher'].search([('state', '=', 'posted'),
                                                                        ('id', 'not in',
                                                                         caja.transaction_ids.mapped('voucher_id').ids),
                                                                        ('journal_id.type', '=', 'sale'),
                                                                        ('operating_unit_id', 'in',
                                                                         caja.box_id.operating_unit_ids.ids),
                                                                        '|', ('rendicion_viaticos_id', '!=', False),
                                                                        ('rendicion_anticipos_id', '!=', False)
                                                                        ])
            for field in res['fields']:
                if field == 'account_voucher_ids':
                    res['fields'][field]['domain'] = [
                        ('id', 'in', account_vouchers.filtered(lambda x: x.currency_id.id == caja.currency.id).ids)]
            res['arch'] = etree.tostring(doc)
        return res

    payment_date = fields.Date('Fecha de pago', default=lambda *a: fields.Date.today(), required=True)
    entry_date = fields.Date('Fecha de asiento', default=lambda *a: fields.Date.today(), required=True)
    account_voucher_ids = fields.Many2many('account.voucher', string=u'Pago a proveedores')
    caja_chica_id = fields.Many2one('grp.caja.chica.tesoreria', string='Caja chica', ondelete='cascade')

    @api.onchange('payment_date')
    def _onchange_payment_date(self):
        self.entry_date = self.payment_date

    @api.multi
    def transfer_account_voucher(self):
        self.ensure_one()
        vouchers = self.mapped('account_voucher_ids')
        out_voucher_ids = vouchers.filtered(lambda x: not x.rendicion_viaticos_id and not x.rendicion_anticipos_id)
        in_voucher_ids = vouchers.filtered(lambda x: x.rendicion_viaticos_id or x.rendicion_anticipos_id)

        vouchers.with_context({'in_cashbox': True}).proforma_voucher()
        in_voucher_ids.write(
            {'date': self.payment_date, 'entry_date': self.entry_date, 'in_cashbox': True, 'state': 'pagado'})
        out_voucher_ids.write({'date': self.payment_date, 'entry_date': self.entry_date})

        new_trasactions = [(0, 0, {'voucher_id': voucher.id, 'ref': self.is_vale_viatico(voucher),
                                   'account_move_id': voucher.move_id.id,
                                   'date': self.payment_date, 'entry_date': self.entry_date,
                                   'partner_id': voucher.partner_id.id,
                                   'amount': voucher.amount * -1}) for voucher in out_voucher_ids]
        new_trasactions.extend([(0, 0, {'voucher_id': voucher.id, 'ref': self.is_vale_viatico(voucher),
                                        'account_move_id': voucher.move_id.id,
                                        'date': self.payment_date, 'entry_date': self.entry_date,
                                        'partner_id': voucher.partner_id.id,
                                        'amount': voucher.amount}) for voucher in in_voucher_ids])

        self.caja_chica_id.write({'transaction_ids': new_trasactions})
        return True

    # TODO: C SPRING 12 GAP_301
    # RAGU: Seteando valores de ref para las lineas de la caja chica
    def is_vale_viatico(self, voucher):
        _vale_rec_name = False
        if voucher.rendicion_viaticos_id:
            _vale_rec_name = u'%s' % (voucher.rendicion_viaticos_id.name_get()[0][1])
        elif voucher.solicitud_viatico_id:
            _vale_rec_name = u'%s' % (voucher.solicitud_viatico_id.name_get()[0][1])
        elif voucher.rendicion_anticipos_id:
            _vale_rec_name = u'%s' % (voucher.rendicion_anticipos_id.name_get()[0][1])
        elif voucher.solicitud_anticipos_id:
            _vale_rec_name = u'%s' % (voucher.solicitud_anticipos_id.name_get()[0][1])

        if not _vale_rec_name:
            vale = self.env['grp.vale.caja'].search(
                [('aprobacion_pago_id', '=', voucher.invoice_id.id)]) if voucher.invoice_id else False
            if vale:
                vale.write({'state': 'pagado'})
                _vale_rec_name = u'Vale(%s)' % (vale.number)
            s = set()
            for line_dr_id in voucher.line_dr_ids.filtered(lambda x: x.reconcile):
                if line_dr_id.move_line_id.invoice.supplier_invoice_number:
                    s.add(line_dr_id.move_line_id.invoice.supplier_invoice_number)
            s = list(s)
            if s:
                _vale_rec_name = u'Factura(%s)' % (', '.join(s))

        if not _vale_rec_name:
            _vale_rec_name = voucher.nro_documento and voucher.nro_documento.find(
                ', ') == -1 and voucher.nro_documento or voucher.number
        return _vale_rec_name
class PurchaseRequest(models.Model):

    _name = 'purchase.request'
    _description = 'Purchase Request'
    _inherit = ['mail.thread', 'ir.needaction_mixin']

    @api.model
    def _company_get(self):
        company_id = self.env['res.company']._company_default_get(self._name)
        return self.env['res.company'].browse(company_id.id)

    @api.model
    def _get_default_requested_by(self):
        return self.env['res.users'].browse(self.env.uid)

    @api.model
    def _get_default_name(self):
        return self.env['ir.sequence'].get('purchase.request')

    @api.model
    def _get_default_origin(self):
        for rec in self:
            rec.origin = rec.name

    @api.model
    def _default_picking_type(self):
        type_obj = self.env['stock.picking.type']
        company_id = self.env.context.get('company_id') or \
            self.env.user.company_id.id
        types = type_obj.search([('code', '=', 'incoming'),
                                 ('warehouse_id.company_id', '=', company_id)])
        if not types:
            types = type_obj.search([('code', '=', 'incoming'),
                                     ('warehouse_id', '=', False)])
        return types[:1]

    @api.multi
    @api.depends('state')
    def _compute_is_editable(self):
        for rec in self:
            if rec.state in ('to_approve', 'to_department_manager_approved','to_accountant_manager_approved','approved', 'rejected'):
                rec.is_editable = False
            else:
                rec.is_editable = True

    @api.multi
    def _track_subtype(self, init_values):
        for rec in self:
            if 'state' in init_values and rec.state == 'to_approve':
                return 'purchase_request.mt_request_to_approve'
            elif 'state' in init_values and rec.state == 'to_department_manager_approved':
                return 'purchase_request.mt_request_to_department_manager_approved'
            elif 'state' in init_values and rec.state == 'to_accountant_manager_approved':
                return 'purchase_request.mt_request_to_accountant_manager_approved'
            elif 'state' in init_values and rec.state == 'approved':
                return 'purchase_request.mt_request_approved'
            elif 'state' in init_values and rec.state == 'rejected':
                return 'purchase_request.mt_request_rejected'
        return super(PurchaseRequest, self)._track_subtype(init_values)
    
    @api.onchange('stock_warehouse')
    def onchange_stock(self):
        if self.stock_warehouse == 1:
            self.stage = 14
        elif self.stock_warehouse == 2:
            self.stage = 4

    name = fields.Char('Request Reference', size=32, required=True,
                       default=_get_default_name,
                       track_visibility='onchange')
    origin = fields.Char('Source Document', size=32, compute=_get_default_origin)
    reject_reason = fields.Char('reject_reason', default=' ')
    date_start = fields.Date('Creation date',
                             help="Date when the user initiated the"
                                  "request.",
                             default=fields.Date.context_today,
                             track_visibility='onchange')
    date_finish = fields.Date('Expected date',
                             help="Date when the Request will"
                                  "Finish.",
                             default=fields.Date.context_today,
                             compute='_check_the_date',
                             track_visibility='onchange')
    requested_by = fields.Many2one('res.users',
                                   'Requested by',
                                   required=True,
                                   track_visibility='onchange',
                                   default=_get_default_requested_by)
    assigned_to = fields.Many2one('res.users', 'Department Managers',
                                  domain=[('x_department_manager', '=', True)],
                                  track_visibility='onchange')
    assigned_to_2 = fields.Many2one('res.users', 'Department Managers',
                                  domain=[('x_department_manager', '=', True)],
                                  track_visibility='onchange')
    assigned_to_3 = fields.Many2one('res.users', 'Projects/Sections Managers',
                                  domain=[('x_project_manager', '=', True)],
                                  track_visibility='onchange')
    description = fields.Text('Description')
    direct_manager_notes = fields.Text('Direct manager notes')
    department_manager_notes = fields.Text('Department manager notes')
    purchase_manager_notes = fields.Text('Purchases manager notes')
    warehouse_manager_notes = fields.Text('Warehouse manager notes')
    accountant_manager_notes = fields.Text('CFO notes')
    executive_manager_notes = fields.Text('Executive manager notes')
    treasurer_manager_notes = fields.Text('Treasurer notes')
    president_manager_notes = fields.Text('Chairman notes')
    company_id = fields.Many2one('res.company', 'Company',
                                 required=True,
                                 default=_company_get,
                                 track_visibility='onchange')
    line_ids = fields.One2many('purchase.request.line', 'request_id',
                               'Products to Purchase',
                               readonly=False,
                               copy=True,
                               track_visibility='onchange')
    state = fields.Selection(selection=_STATES,
                             string='Status',
                             index=True,
                             track_visibility='onchange',
                             required=True,
                             copy=False,
                             default='draft')
    stage = fields.Selection(selection=_STAGES,
                             default=1,
                             string='Stage')
    stock_warehouse = fields.Selection(selection=_WAREHOUSES,
                             string='Stock',on_change="onchange_stock(stock_warehouse)")
    #stock_warehouse = fields.ٍSelection(selection=_WAREHOUSES,string='Stock')
    steps = fields.Selection(selection=_STEPS,
                            string='Technical Specifications Steps')
    request_type = fields.Selection(selection=_TYPES,
                                    default=1,
                                    help = 'Provide request as soon as possible :عاجل',
                                    string='Request Type')
    
    type_reason = fields.Text('Reason')
    explain_type = fields.Char('Explain',compute='_compute_explain')
    department = fields.Many2one('hr.department', 'Department',
                                  track_visibility='onchange')
    project = fields.Many2one('hr.department', 'Project/Section',
                                  track_visibility='onchange')
    is_editable = fields.Boolean(string="Is editable",
                                 compute="_compute_is_editable",
                                 readonly=True)

    picking_type_id = fields.Many2one('stock.picking.type',
                                      'Picking Type', required=True,
                                      default=_default_picking_type)

    ontime = fields.Integer(string='On Time',
                            compute="change_ontime",
                            readonly=True)
    ontime_stage = fields.Integer(string='On Time Stage',
                            compute="change_ontime_stage",
                            readonly=True)
    done1= fields.Char(string='Done',
                       compute="change_done_stage",
                       default='early')
    progress = fields.Float(string='Progress',
                          compute='change_progress',
                          readonly=True)
    color = fields.Integer('Color Index',
                           compute="change_colore_on_kanban")
    
    price_alltotal = fields.Float( string='Total Price', compute='_compute_amount_all', store=True)
    is_direct_notes = fields.Boolean(string="Is Direct Notes",
                                 compute="_compute_is_direct_notes",
                                 readonly=True)
    is_dept_notes = fields.Boolean(string="Is Dept Notes",
                                 compute="_compute_is_dept_notes",
                                 readonly=True)
    is_purchase_notes = fields.Boolean(string="Is Purchase Notes",
                                 compute="_compute_is_purchase_notes",
                                 readonly=True)
    is_warehouse_notes = fields.Boolean(string="Is Warehouse Notes",
                                 compute="_compute_is_warehouse_notes",
                                 readonly=True)
    is_account_notes = fields.Boolean(string="Is Accountant Notes",
                                 compute="_compute_is_account_notes",
                                 readonly=True)
    is_treasure_notes = fields.Boolean(string="Is Treasure Notes",
                                 compute="_compute_is_treasure_notes",
                                 readonly=True)
    is_pres_notes = fields.Boolean(string="Is pres Notes",
                                 compute="_compute_is_pres_notes",
                                 readonly=True)
    is_executive_notes = fields.Boolean(string="Is Executive Notes",
                                 compute="_compute_is_executive_notes",
                                 readonly=True)
    is_usr = fields.Boolean(string="Is Requested by User",
                                 compute="_compute_is_usr",
                                 readonly=True)
    is_stage = fields.Boolean(string="Is Stage User",
                                 compute="_compute_is_stage",
                                 readonly=True)
    is_required = fields.Boolean(string="Is Required User",
                                 compute="_compute_is_required",
                                 readonly=True)
    is_dept_approve = fields.Boolean(string="Is Dept Approve",
                                 compute="_compute_is_dept_approve",
                                 readonly=True)
    is_reject_required = fields.Boolean(string="Is Reject Required User")
    is_request_approval =  fields.Boolean(string="Is Request_Approval User",
                                 compute="_compute_is_request_approval",
                                 readonly=True)
        
    @api.multi
    @api.depends('requested_by')    
    def _compute_is_request_approval(self):
        for rec in self:
            #dep_mang = self.env['res.users'].browse(['res.users'].x_department_manager)
            usr = self.env['res.users'].browse(self.env.uid)
            if usr == rec.requested_by and rec.state == 'draft':
                rec.is_request_approval = True
            elif usr == rec.requested_by and rec.state != 'draft':
                rec.is_request_approval = False
            elif usr != rec.requested_by and rec.state == 'draft':
                rec.is_request_approval = False
            elif usr != rec.requested_by and rec.state != 'draft':
                rec.is_request_approval = False
            #elif 'res.user.x_department_manager' == True:
             #   rec.is_required = True
            else:
                    rec.is_request_approval = False
    @api.multi
    @api.depends('requested_by')            
    def _compute_is_required(self):
        for rec in self:
            #dep_mang = self.env['res.users'].browse(['res.users'].x_department_manager)
            usr = self.env['res.users'].browse(self.env.uid)
            if usr in rec.assigned_to :
                rec.is_required = True
            #elif 'res.user.x_department_manager' == True:
             #   rec.is_required = True
            else:
                rec.is_required = False
    @api.multi
    @api.depends('requested_by')
    def _compute_is_stage(self):
        for rec in self:
            usr = self.env['res.users'].browse(self.env.uid)
            if usr.has_group('__export__.res_groups_56'):
                rec.is_stage = True
            elif usr.has_group('__export__.res_groups_82'):
                rec.is_stage = True
            else:
                if usr.has_group('__export__.res_groups_59'):
                    rec.is_stage = True
                else:
                    rec.is_stage = False
                    
    @api.depends('request_type')
    def _compute_explain(self):
        for rec in self:
            if rec.request_type == 2:
                rec.explain_type = 'Provide request as soon as possible'
            elif rec.request_type == 3:
                rec.explain_type = 'For project and time conditions, the request is made exceptionally from the rules of the regulation'
            else:
                rec.explain_type = ''
    
    @api.multi
    @api.depends('requested_by')            
    def _compute_is_usr(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_usr = True
            else:
                rec.is_usr = False

    @api.multi
    @api.depends('requested_by')
    def _compute_is_direct_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_direct_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_62'):
                    rec.is_direct_notes = True
                else:
                    rec.is_direct_notes= False
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_dept_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_dept_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_61'):
                    rec.is_dept_notes = True
                else:
                    rec.is_dept_notes= False
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_dept_approve(self):
        for rec in self:
            if rec.assigned_to == self.env['res.users'].browse(self.env.uid):
                rec.is_dept_approve = True
            else:
                rec.is_dept_approve = False
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_purchase_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_purchase_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_56'):
                    rec.is_purchase_notes = True
                else:
                    rec.is_purchase_notes= False
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_warehouse_notes(self):
        for rec in self:
            #if rec.requested_by == self.env['res.users'].browse(self.env.uid):
             #   rec.is_warehouse_notes = True
            #else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_82'):
                    rec.is_warehouse_notes = True
                else:
                    rec.is_warehouse_notes= False
    
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_account_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_account_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_59'):
                    rec.is_account_notes = True
                else:
                    rec.is_account_notes= False
    
    @api.multi
    @api.depends('requested_by')                
    def _compute_is_treasure_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_treasure_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_63'):
                    rec.is_treasure_notes = True
                else:
                    rec.is_treasure_notes= False
    @api.multi
    @api.depends('requested_by')
    def _compute_is_pres_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_pres_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('__export__.res_groups_65'):
                    rec.is_pres_notes = True
                else:
                    rec.is_pres_notes= False
    @api.multi
    @api.depends('requested_by')
    def _compute_is_executive_notes(self):
        for rec in self:
            if rec.requested_by == self.env['res.users'].browse(self.env.uid):
                rec.is_executive_notes = True
            else:
                user = self.env['res.users'].browse(self.env.uid)
                if user.has_group('purchase_request.group_purchase_request_manager'):
                    rec.is_executive_notes = True
                else:
                    rec.is_executive_notes= False
    @api.multi
    @api.depends('line_ids.price_total')
    def _compute_amount_all(self):
        for request in self:
            for line in request.line_ids: 
                request.price_alltotal += line.price_total
            #if request.price_alltotal > 0:
             #   request.stage = 5
    
    @api.multi
    def copy(self, default=None):
        default = dict(default or {})
        self.ensure_one()
        default.update({
            'state': 'draft',
            'name': self.env['ir.sequence'].get('purchase.request'),
        })
        return super(PurchaseRequest, self).copy(default)

    @api.model
    def create(self, vals):
        request = super(PurchaseRequest, self).create(vals)
        if vals.get('assigned_to'):
            request.message_subscribe_users(user_ids=[request.assigned_to.id])
        return request

    @api.multi
    def write(self, vals):
        res = super(PurchaseRequest, self).write(vals)
        for request in self:
            if vals.get('assigned_to'):
                self.message_subscribe_users(user_ids=[request.assigned_to.id])
        return res

    @api.multi
    def button_draft(self):
        for rec in self:
            #rec.state = 'draft'
            #rec.stage = 1
            
            if self.state == 'to_approve' and self.direct_manager_notes != False:
                rec.state = 'draft'
                rec.stage = 1
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'to_department_manager_approved' and self.department_manager_notes != False:
                rec.state = 'draft'
                rec.stage = 1
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'to_accountant_manager_approved' and self.accountant_manager_notes != False:
                rec.state = 'draft'
                rec.stage = 1
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'approved' and self.accountant_manager_notes != False:
                rec.state = 'draft'
                rec.stage = 1
                rec.is_reject_required = False
            elif self.state == 'rejected' and self.accountant_manager_notes != False:
                rec.state = 'draft'
                rec.stage = 1
                rec.is_reject_required = False
            else:
                if self.state == 'to_approve':
                    rec.reject_reason = 'You Could Write Reject Reason In direct manager notes'
                    rec.is_reject_required = True
                elif self.state == 'to_department_manager_approved':
                    rec.reject_reason = 'You Could Write Reject Reason In department manager notes'
                    rec.is_reject_required = True
                elif self.state == 'to_accountant_manager_approved':
                    rec.reject_reason = 'You Could Write Reject Reason In CFO manager notes'
                    rec.is_reject_required = True
                elif self.state == 'approved':
                    rec.reject_reason = 'You Could Write Reject Reason In CFO manager notes'
                    rec.is_reject_required = True
                elif self.state == 'rejected':
                    rec.reject_reason = 'You Could Write Reject Reason In CFO manager notes'
                    rec.is_reject_required = True
        return True

    @api.multi
    def button_to_approve(self):
        for rec in self:
            if rec.assigned_to_3:
                rec.state = 'to_approve'
                rec.stage = 2
            elif rec.assigned_to_3 == 0:
                rec.state = 'to_department_manager_approved'
                rec.stage = 2
            else:
                if rec.assigned_to:
                    rec.state = 'to_department_manager_approved'
                    rec.stage = 2
                elif rec.assigned_to == 0:
                    rec.state = 'to_accountant_manager_approved'
                    rec.stage = 4
                else:
                    rec.state = 'to_accountant_manager_approved'
                    rec.stage = 4
        return True
    
    @api.multi
    def button_to_department_manager_approved(self):
        for rec in self:
            rec.state = 'to_department_manager_approved'
        return True

    @api.multi
    def button_to_accountant_manager_approved(self):
        for rec in self:
            rec.state = 'to_accountant_manager_approved'
            rec.stage = 3
        return True
    
    @api.multi
    def button_approved(self):
        for rec in self:
            rec.state = 'approved'
            rec.stage = 5
        return True

    @api.multi
    def button_rejected(self):
        for rec in self:
             
            if self.state == 'to_approve' and self.direct_manager_notes != False:
                rec.state = 'rejected'
                rec.stage = 15
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'to_department_manager_approved' and self.department_manager_notes != False:
                rec.state = 'rejected'
                rec.stage = 15
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'to_accountant_manager_approved' and self.accountant_manager_notes != False:
                rec.state = 'rejected'
                rec.stage = 15
                rec.is_reject_required = False
                #raise ValidationError("You can reject request after write reason in notes:")
                #return False
            elif self.state == 'approved' and self.accountant_manager_notes != False:
                rec.state = 'rejected'
                rec.stage = 15
                rec.is_reject_required = False
            else:
                if self.state == 'to_approve':
                    rec.reject_reason = 'You Could Write Reject Reason In direct manager notes'
                    rec.is_reject_required = True
                elif self.state == 'to_department_manager_approved':
                    rec.reject_reason = 'You Could Write Reject Reason In department manager notes'
                    rec.is_reject_required = True
                elif self.state == 'to_accountant_manager_approved':
                    rec.reject_reason = 'You Could Write Reject Reason In CFO manager notes'
                    rec.is_reject_required = True
                elif self.state == 'approved':
                    rec.reject_reason = 'You Could Write Reject Reason In CFO manager notes'
                    rec.is_reject_required = True
        return True
    
   # _constraints = [
    #    (button_rejected, '"You can reject request after write reason in notes :".'),
        
    #(legacy_doc1_getFilename, '"The file must be a JPG file".'),
#]
    @api.multi
    def _check_the_date(self):
        #for rec in self:
         #   d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
          #  new_date = d1 + datetime.timedelta(days=18)
           # rec.date_finish = new_date
        for rec in self:
            if rec.price_alltotal <= 500 and rec.price_alltotal > 0 and (rec.state == 'to_accountant_manager_approved' or rec.state == 'approved'):
                d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
                new_date = d1 + datetime.timedelta(days=6)
                rec.date_finish = new_date
            elif rec.price_alltotal > 500 and rec.price_alltotal <= 5000 and (rec.state == 'to_accountant_manager_approved' or rec.state == 'approved'):
                d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
                new_date = d1 + datetime.timedelta(days=6)
                rec.date_finish = new_date
            elif rec.price_alltotal > 5000 and rec.price_alltotal <= 100000 and (rec.state == 'to_accountant_manager_approved' or rec.state == 'approved'):
                d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
                new_date = d1 + datetime.timedelta(days=12)
                rec.date_finish = new_date
            elif rec.price_alltotal > 100000 and (rec.state == 'to_accountant_manager_approved' or rec.state == 'approved'):
                d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
                new_date = d1 + datetime.timedelta(days=35)
                rec.date_finish = new_date
            else:
                d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
                new_date = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d')
                rec.date_finish = new_date

    def change_progress(self):
        for rec in self:
            x = rec.stage
            if rec.stage == 15:
                y = 0
            elif rec.stage == 1:
                y = 0
            else:
                y = x * 100 / 14
            rec.progress= y
    
    def change_ontime(self):
        for rec in self:
            if rec.stage == 14 or rec.stage == 15:
                rec.ontime = rec.ontime
            else:
                if rec.state == 'approved':
                    d1 = datetime.datetime.today()
                    d2 = datetime.datetime.strptime((rec.date_finish),'%Y-%m-%d') 
                    d = str((d2-d1).days + 1)
                    rec.ontime = d
                else:
                    rec.ontime = 0

    def change_ontime_stage(self):
        for rec in self:
            d1 = datetime.datetime.today()
            d2 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') 
            d = str((d1-d2).days + 1)
            rec.ontime_stage = d
    def change_done_stage(self):
        for rec in self:
            if rec.price_alltotal <= 500:
                if rec.stage == 1 and rec.ontime_stage > 1:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==2 and rec.ontime_stage > 2:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==3 and rec.ontime_stage > 4:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==4 and rec.ontime_stage > 4:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==5 and rec.ontime_stage > 4:
                    dd = "late"
                    rec.done1 = dd
                #elif rec.stage ==6 and rec.ontime_stage > 4:
                 #   dd = "late"
                  #  rec.done1 = dd
            elif rec.price_alltotal > 500 and rec.price_alltotal <= 5000:
                if rec.stage == 1 and rec.ontime_stage > 1:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==2 and rec.ontime_stage > 2:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==3 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==4 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==5 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                #elif rec.stage ==6 and rec.ontime_stage > 5:
                 #   dd = "late"
                  #  rec.done1 = dd
            elif rec.price_alltotal > 5000 and rec.price_alltotal <= 100000:
                if rec.stage == 1 and rec.ontime_stage > 1:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==2 and rec.ontime_stage > 2:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==3 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==4 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==5 and rec.ontime_stage > 5:
                    dd = "late"
                    rec.done1 = dd
                #elif rec.stage ==6 and rec.ontime_stage > 5:
                 #   dd = "late"
                  #  rec.done1 = dd
            elif rec.price_alltotal > 100000:
                if rec.stage == 1 and rec.ontime_stage > 1:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==2 and rec.ontime_stage > 2:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==3 and rec.ontime_stage > 7:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==4 and rec.ontime_stage > 7:
                    dd = "late"
                    rec.done1 = dd
                elif rec.stage ==5 and rec.ontime_stage > 7:
                    dd = "late"
                    rec.done1 = dd
                #elif rec.stage ==6 and rec.ontime_stage > 7:
                 #   dd = "late"
                  #  rec.done1 = dd
                elif (rec.stage ==6 or rec.stage ==7 or rec.stage ==8 or rec.stage ==9)  and rec.ontime_stage > 15:
                    dd = "late"
                    rec.done1 = dd
                elif (rec.stage ==10 or rec.stage ==11 or rec.stage ==12 or rec.stage ==13)  and rec.ontime_stage > 12:
                    dd = "late"
                    rec.done1 = dd

    def change_colore_on_kanban(self):   
        for record in self:
            color = 0
            if record.progress == 100:
                color = 5
            else:
                if record.ontime < 0:
                    color = 9
                elif record.ontime == 0:
                    if record.state == 'to_accountant_manager_approved':
                        color = 3
                    elif record.state == 'to_department_manager_approved':
                        color = 3
                    elif record.state == 'rejected':
                        color = 6
                    else:
                        color = 3
                elif record.ontime > 0:
                    color = 5
                elif record.progress == 100:
                    color = 5
                elif record.state == 'rejected':
                    color = 1
            record.color = color
            
    @api.multi
    def write(self,vals):
        # Your logic goes here or call your method
        super(PurchaseRequest, self).write(vals)
        for ss in self:
            if ss.state == 'rejected':
                ss.env.cr.execute("UPDATE purchase_request SET stage = 15 WHERE id = '%s' " %(ss.id))
        return True    
Exemple #20
0
class BookingCommissionMakeSettle(models.TransientModel):
    _name = "booking.commission.make.settle"

    date_to = fields.Date('Up to', required=True, default=fields.Date.today())
    agents = fields.Many2many(comodel_name='res.partner',
                              domain="[('agent', '=', True)]")

    def _get_period_start(self, agent, date_to):
        if isinstance(date_to, basestring):
            date_to = fields.Date.from_string(date_to)
        if agent.settlement == 'monthly':
            return date(month=date_to.month, year=date_to.year, day=1)
        elif agent.settlement == 'quaterly':
            # Get first month of the date quarter
            month = ((date_to.month - 1) // 3 + 1) * 3
            return date(month=month, year=date_to.year, day=1)
        elif agent.settlement == 'semi':
            if date_to.month > 6:
                return date(month=7, year=date_to.year, day=1)
            else:
                return date(month=1, year=date_to.year, day=1)
        elif agent.settlement == 'annual':
            return date(month=1, year=date_to.year, day=1)
        else:
            raise exceptions.Warning(_("Settlement period not valid."))

    def _get_next_period_date(self, agent, current_date):
        if isinstance(current_date, basestring):
            current_date = fields.Date.from_string(current_date)
        if agent.settlement == 'monthly':
            return current_date + relativedelta(months=1)
        elif agent.settlement == 'quaterly':
            return current_date + relativedelta(months=3)
        elif agent.settlement == 'semi':
            return current_date + relativedelta(months=6)
        elif agent.settlement == 'annual':
            return current_date + relativedelta(years=1)
        else:
            raise exceptions.Warning(_("Settlement period not valid."))

    @api.multi
    def action_settle(self):
        self.ensure_one()
        # agent_line_obj = self.env['account.invoice.line.agent']
        # settlement_obj = self.env['booking.commission.settlement']
        # settlement_line_obj = self.env['booking.commission.settlement.line']
        settlement_ids = []
        sett_to = fields.Date.to_string(date(year=1900, month=1, day=1))
        if not self.agents:
            self.agents = self.env['res.partner'].search([('agent', '=', True)
                                                          ])
        for agent in self.agents:
            agent_lines = self.env['account.invoice.line.agent'].search(
                [('agent', '=', agent.id), ('settled', '=', False),
                 ('invoice.type', 'in', ('out_invoice', 'out_refund'))],
                order='invoice_date')
            if not agent_lines:
                continue
            for company in agent_lines.mapped('invoice_line.company_id'):
                agent_lines_company = agent_lines.filtered(
                    lambda agent_l: agent_l.invoice_line.company_id == company)
                if not agent_lines_company:
                    continue
                for agent_line in agent_lines_company:
                    agent_line_not_paid = (agent_line.invoice.state != 'paid')
                    if agent.commission.invoice_state == 'paid' and \
                            agent_line_not_paid:
                        continue
                    if agent_line.invoice_date <= sett_to:
                        continue
                    # if agent_line.invoice_date > sett_to:
                    sett_from = self._get_period_start(agent,
                                                       agent_line.invoice_date)
                    sett_to = fields.Date.to_string(
                        self._get_next_period_date(agent, sett_from) -
                        timedelta(days=1))
                    sett_from = fields.Date.to_string(sett_from)
                    settlement = self.env[
                        'booking.commission.settlement'].create({
                            'agent':
                            agent.id,
                            'date_from':
                            sett_from,
                            'date_to':
                            sett_to,
                            'company_id':
                            company.id,
                        })
                    settlement_ids.append(settlement.id)
                    invoice_line = agent_line.invoice_line
                    self.env['booking.commission.settlement.line'].create({
                        'settlement':
                        settlement.id,
                        'agent_line': [(6, 0, [agent_line.id])],
                        'commission_tax_id':
                        (invoice_line.commission_tax_id
                         and invoice_line.commission_tax_id.id or None),
                    })
        if len(settlement_ids):
            return {
                'name': _('Created Settlements'),
                'type': 'ir.actions.act_window',
                'views': [[False, 'list'], [False, 'form']],
                'res_model': 'booking.commission.settlement',
                'domain': [['id', 'in', settlement_ids]],
            }
        else:
            return {'type': 'ir.actions.act_window_close'}
Exemple #21
0
class AccountAssetCategory(models.Model):
    _name = 'account.asset.category'
    _description = 'Asset category'

    active = fields.Boolean(default=True)
    name = fields.Char(required=True, index=True, string="Asset Type")
    account_analytic_id = fields.Many2one('account.analytic.account',
                                          string='Analytic Account')
    account_asset_id = fields.Many2one(
        'account.account',
        string='Asset Account',
        required=True,
        domain=[('internal_type', '=', 'other'), ('deprecated', '=', False)],
        help=
        "Account used to record the purchase of the asset at its original price."
    )
    account_depreciation_id = fields.Many2one(
        'account.account',
        string='Depreciation Entries: Asset Account',
        required=True,
        domain=[('internal_type', '=', 'other'), ('deprecated', '=', False)],
        help=
        "Account used in the depreciation entries, to decrease the asset value."
    )
    account_depreciation_expense_id = fields.Many2one(
        'account.account',
        string='Depreciation Entries: Expense Account',
        required=True,
        domain=[('internal_type', '=', 'other'), ('deprecated', '=', False)],
        oldname='account_income_recognition_id',
        help=
        "Account used in the periodical entries, to record a part of the asset as expense."
    )
    journal_id = fields.Many2one('account.journal',
                                 string='Journal',
                                 required=True)
    company_id = fields.Many2one(
        'res.company',
        string='Company',
        required=True,
        default=lambda self: self.env['res.company']._company_default_get(
            'account.asset.category'))
    method = fields.Selection(
        [('linear', 'Linear'), ('degressive', 'Degressive')],
        string='Computation Method',
        required=True,
        default='linear',
        help=
        "Choose the method to use to compute the amount of depreciation lines.\n"
        "  * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
        "  * Degressive: Calculated on basis of: Residual Value * Degressive Factor"
    )
    method_number = fields.Integer(
        string='Number of Depreciations',
        default=5,
        help="The number of depreciations needed to depreciate your asset")
    method_period = fields.Integer(
        string='Period Length',
        default=1,
        help="State here the time between 2 depreciations, in months",
        required=True)
    method_progress_factor = fields.Float('Degressive Factor', default=0.3)
    method_time = fields.Selection(
        [('number', 'Number of Depreciations'), ('end', 'Ending Date')],
        string='Time Method',
        required=True,
        default='number',
        help=
        "Choose the method to use to compute the dates and number of depreciation lines.\n"
        "  * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n"
        "  * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."
    )
    method_end = fields.Date('Ending date')
    prorata = fields.Boolean(
        string='Prorata Temporis',
        help=
        'Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first of January'
    )
    open_asset = fields.Boolean(
        string='Auto-confirm Assets',
        help=
        "Check this if you want to automatically confirm the assets of this category when created by invoices."
    )
    group_entries = fields.Boolean(
        string='Group Journal Entries',
        help=
        "Check this if you want to group the generated entries by categories.")
    type = fields.Selection([('sale', 'Sale: Revenue Recognition'),
                             ('purchase', 'Purchase: Asset')],
                            required=True,
                            index=True,
                            default='purchase')

    @api.onchange('account_asset_id')
    def onchange_account_asset(self):
        self.account_depreciation_id = self.account_asset_id

    @api.onchange('type')
    def onchange_type(self):
        if self.type == 'sale':
            self.prorata = True
            self.method_period = 1
        else:
            self.method_period = 12
class wizard_create_template_lines(models.TransientModel):
    _name = 'wizard.create.template.lines'
    _rec_name = 'calendar_template_id'

    #===========================================================================
    # COLUMNS
    #===========================================================================
    calendar_template_id = fields.Many2one('calendar.template',
                                           string='Calendar',
                                           required=True,
                                           ondelete='cascade')
    monday = fields.Boolean(default=True)
    tuesday = fields.Boolean(default=True)
    wednesday = fields.Boolean(default=True)
    thursday = fields.Boolean(default=True)
    friday = fields.Boolean(default=True)
    saturday = fields.Boolean(default=False)
    sunday = fields.Boolean(default=False)

    start_date = fields.Date()
    end_date = fields.Date()

    hour_start0 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end0 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number0 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start1 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end1 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number1 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start2 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end2 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number2 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start3 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end3 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number3 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start4 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end4 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number4 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start5 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end5 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number5 = fields.Float(string='Hour number', digits=(16, 2))
    hour_start6 = fields.Float(string='Hour start', digits=(16, 2))
    hour_end6 = fields.Float(string='Hour end', digits=(16, 2))
    hour_number6 = fields.Float(string='Hour number', digits=(16, 2))

    @api.model
    def default_get(self, fields_list):
        res = super(wizard_create_template_lines,
                    self).default_get(fields_list=fields_list)
        cal_obj = self.env['calendar.template']
        cal = cal_obj.browse(self._context.get('active_id'))
        vals = {
            'start_date': cal.start_date,
            'end_date': cal.end_date,
            'calendar_template_id': cal.id,
        }

        res.update(vals)
        return res

    def create_line(self, dow, start_date):
        start, end, number = 'hour_start%(dow)s' % {
            'dow': dow
        }, 'hour_end%(dow)s' % {
            'dow': dow
        }, 'hour_number%(dow)s' % {
            'dow': dow
        }
        line_template_obj = self.env['calendar.template.line']
        # Le bloc de code ci-dessous permet d'enregistrer les dates dans la bonne "timezone" (celle du serveur)
        # car l'utilisateur saisit dans sa timezone 'ex GMT+1'
        server_tz = "UTC"
        dt_value = start_date
        src_tz = pytz.timezone(server_tz)
        dst_tz = pytz.timezone(self._context.get('tz'))
        src_dt = dst_tz.localize(dt_value, is_dst=True)
        dt_value = src_dt.astimezone(src_tz)
        if self[start] > self[end]:
            end_dt_value = dt_value + datetime.timedelta(days=1)
        else:
            end_dt_value = dt_value

        vals = {
            'calendar_template_id': self.calendar_template_id.id,
            'hour': self[number],
            'start_date':
            dt_value + datetime.timedelta(minutes=self[start] * 60),
            'end_date':
            end_dt_value + datetime.timedelta(minutes=self[end] * 60),
        }
        return line_template_obj.create(vals)

    def _check_date_and_timezone(self):
        result, msg = True, ''
        # Commenté pour pouvoir génerer une ligne a cheval sur deux jours
        #         if self.start_date > self.end_date:
        #             result = False
        #             msg += "\n The start_date must be inferior to the end_date."

        if not self.env.user.tz:
            result = False
            msg += "\n The timezone is not set on the user."

        return (result, msg)

    @api.one
    def generate_lines(self):
        check, msg = self._check_date_and_timezone()
        if not check:
            raise except_orm(_('Error'), _(msg))

        line_template_obj = self.env['calendar.template.line']
        template_line_ids = line_template_obj.search([
            ('calendar_template_id', '=', self.calendar_template_id.id),
            ('start_date', '>=', self.start_date),
            ('start_date', '<=', self.end_date)
        ])
        if template_line_ids:
            template_line_ids.unlink()

        start_date = datetime.datetime.strptime(self.start_date, '%Y-%m-%d')
        end_date = datetime.datetime.strptime(
            self.end_date, '%Y-%m-%d') + datetime.timedelta(days=1)
        interval_days = (end_date - start_date).days
        cpt = 1
        while cpt <= interval_days:
            # Traitement ici
            dow = start_date.isoweekday()
            for i, j in enumerate(AVAILABLE_DAYS):
                if self[j[0]] and dow == i + 1:
                    self.create_line(i, start_date)

            # On incremente la date à la fin de la boucle
            start_date += datetime.timedelta(days=1)
            cpt += 1

        return {'type': 'ir.actions.act_window_close'}
Exemple #23
0
class AccountAssetDepreciationLine(models.Model):
    _name = 'account.asset.depreciation.line'
    _description = 'Asset depreciation line'

    name = fields.Char(string='Depreciation Name', required=True, index=True)
    sequence = fields.Integer(required=True)
    asset_id = fields.Many2one('account.asset.asset',
                               string='Asset',
                               required=True,
                               ondelete='cascade')
    parent_state = fields.Selection(related='asset_id.state',
                                    string='State of Asset')
    amount = fields.Float(string='Current Depreciation',
                          digits=0,
                          required=True)
    remaining_value = fields.Float(string='Next Period Depreciation',
                                   digits=0,
                                   required=True)
    depreciated_value = fields.Float(string='Cumulative Depreciation',
                                     required=True)
    depreciation_date = fields.Date('Depreciation Date', index=True)
    move_id = fields.Many2one('account.move', string='Depreciation Entry')
    move_check = fields.Boolean(compute='_get_move_check',
                                string='Linked',
                                track_visibility='always',
                                store=True)
    move_posted_check = fields.Boolean(compute='_get_move_posted_check',
                                       string='Posted',
                                       track_visibility='always',
                                       store=True)

    @api.multi
    @api.depends('move_id')
    def _get_move_check(self):
        for line in self:
            line.move_check = bool(line.move_id)

    @api.multi
    @api.depends('move_id.state')
    def _get_move_posted_check(self):
        for line in self:
            line.move_posted_check = True if line.move_id and line.move_id.state == 'posted' else False

    @api.multi
    def create_move(self, post_move=True):
        created_moves = self.env['account.move']
        for line in self:
            category_id = line.asset_id.category_id
            depreciation_date = self.env.context.get(
                'depreciation_date'
            ) or line.depreciation_date or fields.Date.context_today(self)
            company_currency = line.asset_id.company_id.currency_id
            current_currency = line.asset_id.currency_id
            amount = current_currency.compute(line.amount, company_currency)
            sign = (category_id.journal_id.type == 'purchase'
                    or category_id.journal_id.type == 'sale' and 1) or -1
            asset_name = line.asset_id.name + ' (%s/%s)' % (
                line.sequence, line.asset_id.method_number)
            move_line_1 = {
                'name':
                asset_name,
                'account_id':
                category_id.account_depreciation_id.id,
                'debit':
                0.0,
                'credit':
                amount,
                'journal_id':
                category_id.journal_id.id,
                'partner_id':
                line.asset_id.partner_id.id,
                'analytic_account_id':
                category_id.account_analytic_id.id
                if category_id.type == 'sale' else False,
                'currency_id':
                company_currency != current_currency and current_currency.id
                or False,
                'amount_currency':
                company_currency != current_currency and -sign * line.amount
                or 0.0,
            }
            move_line_2 = {
                'name':
                asset_name,
                'account_id':
                category_id.account_depreciation_expense_id.id,
                'credit':
                0.0,
                'debit':
                amount,
                'journal_id':
                category_id.journal_id.id,
                'partner_id':
                line.asset_id.partner_id.id,
                'analytic_account_id':
                category_id.account_analytic_id.id
                if category_id.type == 'purchase' else False,
                'currency_id':
                company_currency != current_currency and current_currency.id
                or False,
                'amount_currency':
                company_currency != current_currency and sign * line.amount
                or 0.0,
            }
            move_vals = {
                'ref': line.asset_id.code,
                'date': depreciation_date or False,
                'journal_id': category_id.journal_id.id,
                'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
            }
            move = self.env['account.move'].create(move_vals)
            line.write({'move_id': move.id, 'move_check': True})
            created_moves |= move

        if post_move and created_moves:
            created_moves.filtered(lambda m: any(
                m.asset_depreciation_ids.mapped(
                    'asset_id.category_id.open_asset'))).post()
        return [x.id for x in created_moves]

    @api.multi
    def create_grouped_move(self, post_move=True):
        if not self.exists():
            return []

        created_moves = self.env['account.move']
        category_id = self[
            0].asset_id.category_id  # we can suppose that all lines have the same category
        depreciation_date = self.env.context.get(
            'depreciation_date') or fields.Date.context_today(self)
        amount = 0.0
        for line in self:
            # Sum amount of all depreciation lines
            company_currency = line.asset_id.company_id.currency_id
            current_currency = line.asset_id.currency_id
            amount += current_currency.compute(line.amount, company_currency)

        name = category_id.name + _(' (grouped)')
        move_line_1 = {
            'name':
            name,
            'account_id':
            category_id.account_depreciation_id.id,
            'debit':
            0.0,
            'credit':
            amount,
            'journal_id':
            category_id.journal_id.id,
            'analytic_account_id':
            category_id.account_analytic_id.id
            if category_id.type == 'sale' else False,
        }
        move_line_2 = {
            'name':
            name,
            'account_id':
            category_id.account_depreciation_expense_id.id,
            'credit':
            0.0,
            'debit':
            amount,
            'journal_id':
            category_id.journal_id.id,
            'analytic_account_id':
            category_id.account_analytic_id.id
            if category_id.type == 'purchase' else False,
        }
        move_vals = {
            'ref': category_id.name,
            'date': depreciation_date or False,
            'journal_id': category_id.journal_id.id,
            'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
        }
        move = self.env['account.move'].create(move_vals)
        self.write({'move_id': move.id, 'move_check': True})
        created_moves |= move

        if post_move and created_moves:
            self.post_lines_and_close_asset()
            created_moves.post()
        return [x.id for x in created_moves]

    api.multi

    def post_lines_and_close_asset(self):
        # we re-evaluate the assets to determine whether we can close them
        for line in self:
            line.log_message_when_posted()
            asset = line.asset_id
            if asset.currency_id.is_zero(asset.value_residual):
                asset.message_post(body=_("Document closed."))
                asset.write({'state': 'close'})

    @api.multi
    def log_message_when_posted(self):
        def _format_message(message_description, tracked_values):
            message = ''
            if message_description:
                message = '<span>%s</span>' % message_description
            for name, values in tracked_values.iteritems():
                message += '<div> &nbsp; &nbsp; &bull; <b>%s</b>: ' % name
                message += '%s</div>' % values
            return message

        for line in self:
            if line.move_id and line.move_id.state == 'draft':
                partner_name = line.asset_id.partner_id.name
                currency_name = line.asset_id.currency_id.name
                msg_values = {
                    _('Currency'): currency_name,
                    _('Amount'): line.amount
                }
                if partner_name:
                    msg_values[_('Partner')] = partner_name
                msg = _format_message(_('Depreciation line posted.'),
                                      msg_values)
                line.asset_id.message_post(body=msg)

    @api.multi
    def unlink(self):
        for record in self:
            if record.move_check:
                if record.asset_id.category_id.type == 'purchase':
                    msg = _("You cannot delete posted depreciation lines.")
                else:
                    msg = _("You cannot delete posted installment lines.")
                raise UserError(msg)
        return super(AccountAssetDepreciationLine, self).unlink()
class ResPartner(models.Model):
    _inherit = 'res.partner'

    COOPERATIVE_STATE_CUSTOMER = ['up_to_date', 'alert', 'delay', 'exempted']

    SEX_SELECTION = [
        ('m', 'male'),
        ('f', 'female'),
        ('o', 'other'),
    ]

    # New Column Section
    is_member = fields.Boolean('Is Member',
                               compute="_compute_is_member",
                               store=True,
                               readonly=True)

    is_former_member = fields.Boolean("Is Former Member",
                                      compute="_compute_is_former_member",
                                      store=True, readonly=True)

    is_former_associated_people = fields.Boolean(
        "Is Former Associated People",
        compute="_compute_is_former_associated_people",
        store=True, readonly=True)

    is_interested_people = fields.Boolean(
        "Is Interested People",
        compute="_compute_is_interested_people",
        readonly=True, store=True)

    is_worker_member = fields.Boolean(
        "Is Worker Member",
        compute="_compute_is_worker_member",
        readonly=True, store=True)

    is_unpayed = fields.Boolean(
        string='Unpayed', help="Check this box, if the partner has late"
        " payments for him capital subscriptions. this will prevent him"
        " to buy.")

    is_unsubscribed = fields.Boolean(
        string='Unsubscribed', store=True, help="Computed field."
        " This box is checked if the user is not linked"
        " to a template registration.",
        compute="_compute_is_unsubscribed")

    sex = fields.Selection(
        selection=SEX_SELECTION, string='Sex')

    temp_coop_number = fields.Char('Temporary number')

    is_underclass_population = fields.Boolean(
        'is Underclass Population',
        compute='_compute_is_underclass_population')

    contact_origin_id = fields.One2many(
        'event.registration', 'partner_id', string='Contact Origin')

    is_deceased = fields.Boolean(string='Is Deceased')

    date_of_death = fields.Date(string="Date of Death")

    age = fields.Integer(
        string="Age", compute='_compute_age')

    partner_owned_share_ids = fields.One2many(
        'res.partner.owned.share',
        'partner_id',
        string="Partner Owned Shares")

    total_partner_owned_share = fields.Integer(
        string="Total Owned Shares",
        compute="_compute_total_partner_owned_share",
        store=True)

    is_associated_people = fields.Boolean(
        string='Is Associated People', store=True,
        compute='_compute_is_associated_people')

    is_designated_buyer = fields.Boolean(
        string='Designated buyer'
    )

    deactivated_date = fields.Date()

    welcome_email = fields.Boolean(
        string='Welcome email sent', default=False)

    # Important : Overloaded Field Section
    customer = fields.Boolean(
        compute='_compute_customer', store=True, readonly=True)

    # Note we use selection instead of selection_add, to have a correct
    # order in the status widget
    cooperative_state = fields.Selection(
        selection=EXTRA_COOPERATIVE_STATE_SELECTION, default='not_concerned')

    working_state = fields.Selection(selection=EXTRA_COOPERATIVE_STATE_SELECTION)

    nb_associated_people = fields.Integer(
        'Number of Associated People',
        compute="_compute_number_of_associated_people",
        store=True)

    parent_member_num = fields.Integer(string="Parent Number",
                                       related='parent_id.barcode_base',
                                       store=True)
    badge_distribution_date = fields.Date(string="Badge Distribution")
    badge_to_distribute = fields.Boolean(string="Badge to distribute",
                                         store=True,
                                         compute="compute_badge_to_distribute")
    badge_print_date = fields.Date(string="Badge Print Date")
    contact_us_message = fields.Html(
        string="Contact Us Message", translate=True)

    force_customer = fields.Boolean(string="Force Customer", default=False)

    inform_ids = fields.Many2many(
        comodel_name='res.partner.inform', string='Informé que')

    shift_type = fields.Selection(
        string='Shift type',
        compute='_compute_shift_type',
        store=True
    )

    current_template_name = fields.Char(
        string='Current Template',
        compute='_compute_current_template',
        store=True
    )

    is_minor_child = fields.Boolean(string='Enfant mineur')
    unsubscription_date = fields.Date(
        string='Unsubscription Date',
        compute='_compute_is_unsubscribed',
        store=True
    )

    leader_ids = fields.Many2many(
        comodel_name='res.partner',
        relation='partner_leader_rel',
        column1='leader_id',
        column2='partner_id',
        compute='_compute_current_template',
        string='Shift Leaders'
    )

    @api.onchange('birthdate')
    def _onchange_birthdate(self):
        if self.birthdate and self.is_minor_child:
            self.check_minor_child_birthdate(
                self.birthdate, self.is_minor_child
            )

    # Constraint Section
    @api.multi
    @api.constrains('birthdate')
    def _check_partner_birthdate(self):
        """ Check minor child's birth date """
        for partner in self:
            if partner.is_minor_child and partner.birthdate:
                partner.check_minor_child_birthdate(
                    partner.birthdate, partner.is_minor_child
                )

    @api.multi
    @api.constrains('is_member',
                    'parent_id',
                    'is_associated_people',
                    'total_partner_owned_share')
    def _check_partner_type(self):
        '''
        @Function to add a constraint on partner type
            - If a partner has shares, he cannot be an associated member
        '''
        for partner in self:
            partner_parent = partner.parent_id
            if partner_parent and partner_parent.is_member and \
                    partner.total_partner_owned_share > 0:
                raise ValidationError(
                    _("You can't be an " +
                      "associated people if you have shares ! " +
                      "Empty the parent_id field to be allowed " +
                      "to write others changes"))

    @api.multi
    @api.constrains('nb_associated_people')
    def _check_number_of_associated_people(self):
        '''
        @Function to add a constraint on member
            - A member cannot have number_of_associated_people higher than max.
        '''
        config_param_env = self.env['ir.config_parameter']
        key_max_nb = 'coop_membership.max_nb_associated_people'
        max_nb = eval(config_param_env.get_param(key_max_nb, '0'))
        key_avail_check = 'coop_membership.associated_people_available'
        avail_check = config_param_env.get_param(key_avail_check, 'unlimited')
        for rec in self:
            if avail_check == 'limited' and rec.is_member and \
                    rec.nb_associated_people > max_nb:
                raise ValidationError(_("The maximum number of " +
                                        "associated people has been exceeded."))

    @api.multi
    @api.depends('is_associated_people', 'parent_id.shift_type')
    def _compute_shift_type(self):
        for partner in self.sorted(key=lambda p: p.is_associated_people):
            if partner.is_associated_people and partner.parent_id:
                partner.shift_type = partner.parent_id.shift_type
            else:
                partner.shift_type = 'standard'

    @api.multi
    @api.depends('badge_distribution_date', 'badge_print_date')
    def compute_badge_to_distribute(self):
        for record in self:
            badge_to_distribute = False
            if record.badge_print_date:
                if not record.badge_distribution_date or\
                        record.badge_distribution_date < record.badge_print_date:
                    badge_to_distribute = True
            record.badge_to_distribute = badge_to_distribute

    @api.multi
    def force_customer_button(self):
        for record in self:
            record.force_customer = True
        return True

    @api.multi
    def force_supplier_button(self):
        for record in self:
            record.force_customer = False
        return True

    @api.multi
    def update_badge_print_date(self):
        for record in self:
            record.badge_print_date = fields.Date.context_today(self)

    # Compute Section
    @api.multi
    @api.depends('birthdate')
    def _compute_age(self):
        for partner in self:
            if partner.birthdate:
                d1 = datetime.strptime(partner.birthdate, "%Y-%m-%d").date()
                d2 = date.today()
                partner.age = relativedelta(d2, d1).years

    @api.multi
    def set_messages_contact(self):
        self.ensure_one()
        message = self.env.user.company_id.contact_us_message
        self.write({
            'contact_us_message': message
        })
        return True

    @api.multi
    @api.depends(
        'tmpl_reg_line_ids.date_begin', 'tmpl_reg_line_ids.date_end')
    def _compute_is_unsubscribed(self):
        for partner in self:
            # Optimization. As this function will be call by cron
            # every night, we do not realize a write, that would raise
            # useless triger for state
            today = fields.Date.context_today(self)
            leave_none_defined = partner.leave_ids.filtered(
                lambda l: l.start_date <= today <= l.stop_date
                and l.non_defined_leave and l.state == 'done')
            no_reg_line = partner.active_tmpl_reg_line_count == 0

            is_unsubscribed = (no_reg_line and not leave_none_defined)
            if partner.is_unsubscribed != is_unsubscribed:
                partner.is_unsubscribed = is_unsubscribed

            if partner.active_tmpl_reg_line_count:
                partner.unsubscription_date = False

            # Auto remove partner from squadleader of team
            if partner.is_unsubscribed:
                templates = self.env['shift.template'].search([
                    ('user_ids', 'in', partner.id),
                ])
                # TODO Check here to re add this partner as a leader
                for template in templates:
                    if len(template.user_ids) >= 2:
                        template.write({
                            'user_ids': [(3, partner.id)],
                            'removed_user_ids': [(4, partner.id)],
                        })

                tmpl_reg_lines = partner.tmpl_reg_line_ids.filtered(
                    lambda tmpl_rgl: tmpl_rgl.date_end).sorted(
                    lambda tmpl_rgl: tmpl_rgl.id
                )

                if tmpl_reg_lines:
                    partner.unsubscription_date = fields.Date.from_string(
                        tmpl_reg_lines[-1].date_end
                    )

    @api.multi
    @api.depends('fundraising_partner_type_ids')
    def _compute_is_underclass_population(self):
        xml_id = self.env.ref('coop_membership.underclass_population_type').id
        for partner in self:
            partner.is_underclass_population =\
                xml_id in partner.fundraising_partner_type_ids.ids

    @api.multi
    @api.depends('partner_owned_share_ids',
                 'partner_owned_share_ids.owned_share')
    def _compute_total_partner_owned_share(self):
        for partner in self:
            partner.total_partner_owned_share = \
                sum(partner_ownedshare.owned_share
                    for partner_ownedshare in partner.partner_owned_share_ids)
            # Update when number of shares reaches "0"
            partner._update_when_number_of_shares_reaches_0()

    @api.multi
    @api.depends('total_partner_owned_share')
    def _compute_is_member(self):
        '''
        @Function to identify if a partner is a member:
            - A partner is a member if he/she has shares of any type
        '''
        for partner in self:
            partner.is_member = partner.total_partner_owned_share > 0

    @api.multi
    @api.depends("total_partner_owned_share")
    def _compute_is_former_member(self):
        '''
        @Function to compute the value of is former member
        '''
        for partner in self:
            if partner.total_partner_owned_share == 0:
                fundraising_count = \
                    self.env['account.invoice'].sudo().search_count(
                        [('partner_id', '=', partner.id),
                         ('fundraising_category_id', '!=', False),
                         ('state', 'in', ('open', 'paid'))])
                if fundraising_count:
                    partner.is_former_member = True
                else:
                    partner.is_former_member = False
            else:
                partner.is_former_member = False

    @api.multi
    @api.depends('is_member', 'is_associated_people',
                 'is_former_member', 'is_former_associated_people', 'supplier')
    def _compute_is_interested_people(self):
        '''
        @Function to compute data for the field is_interested_people
            - True if: a partner is not a member AND is not associated people
            AND is not a supplier
        '''
        for partner in self:
            partner.is_interested_people = \
                (not partner.is_member) and \
                (not partner.is_associated_people) and \
                (not partner.is_former_associated_people) and \
                (not partner.is_former_member) and \
                (not partner.supplier) or False

    @api.multi
    @api.depends('is_member', 'parent_id.is_member')
    def _compute_is_associated_people(self):
        for partner in self:
            partner.is_associated_people =\
                partner.parent_id and \
                partner.parent_id.is_member and (not partner.is_member)

    @api.multi
    @api.depends('parent_id', 'parent_id.is_former_member')
    def _compute_is_former_associated_people(self):
        for partner in self:
            partner.is_former_associated_people = \
                partner.parent_id and partner.parent_id.is_former_member

    @api.multi
    @api.depends(
        'partner_owned_share_ids',
        'partner_owned_share_ids.category_id',
        'partner_owned_share_ids.category_id.is_worker_capital_category',
        'partner_owned_share_ids.owned_share')
    def _compute_is_worker_member(self):
        '''
        @Function to compute data for the field is_worker_member:
            - True if a member has shares in Worker Capital Category
        '''
        partner_owned_share_env = self.env['res.partner.owned.share']
        for partner in self:
            worker_shares = partner_owned_share_env.sudo().search_count(
                [('partner_id', '=', partner.id),
                 ('category_id.is_worker_capital_category', '=', True),
                 ('owned_share', '>', 0)])
            partner.is_worker_member = worker_shares and True or False

    @api.depends(
        'working_state', 'is_unpayed', 'is_unsubscribed',
        'is_worker_member', 'is_associated_people',
        'parent_id.cooperative_state')
    @api.multi
    def _compute_cooperative_state(self):
        for partner in self:
            if partner.is_associated_people:
                # Associated People
                partner.cooperative_state = partner.parent_id.cooperative_state
            elif partner.is_worker_member:
                # Type A Subscriptor
                if partner.is_unsubscribed:
                    partner.cooperative_state = 'unsubscribed'
                elif partner.is_unpayed:
                    partner.cooperative_state = 'unpayed'
                else:
                    partner.cooperative_state = partner.working_state
            else:
                partner.cooperative_state = 'not_concerned'

    @api.depends('cooperative_state', 'force_customer')
    @api.multi
    def _compute_customer(self):
        for partner in self:
            if partner.cooperative_state in\
                    self.COOPERATIVE_STATE_CUSTOMER or partner.force_customer:
                partner.customer = True
            else:
                partner.customer = False

    @api.depends('child_ids')
    @api.multi
    def _compute_number_of_associated_people(self):
        for partner in self:
            if (partner.is_member or partner.is_former_member) and \
                    partner.child_ids:
                partner.nb_associated_people = \
                    sum([(p.is_associated_people or
                          p.is_former_associated_people) and 1 or 0
                         for p in partner.child_ids])
            else:
                partner.nb_associated_people = 0

    @api.multi
    @api.depends('tmpl_reg_ids.is_current')
    def _compute_current_template(self):
        for partner in self:
            current_template = False
            reg = partner.tmpl_reg_ids.filtered(
                lambda r: r.is_current)
            if reg:
                current_template = reg[0].shift_template_id
            else:
                reg = partner.tmpl_reg_ids.filtered(
                    lambda r: r.is_future)
                if reg:
                    current_template = reg[0].shift_template_id
            if current_template:
                partner.leader_ids = current_template.user_ids
                partner.current_template_name = current_template.name

    # Overload Section
    @api.model
    def search(self, args, offset=0, limit=None, order=None, count=False):
        if self._context.get('allow_to_search_barcode_base', False):
            barcode_base_clauses = filter(
                lambda clause: clause[0] == 'barcode_base'
                and not clause[-1].isdigit(),
                args
            )
            for barcode_base_clause in barcode_base_clauses:
                barcode_base_clause[0] = u'display_name'
                barcode_base_clause[1] = u'ilike'
        return super(ResPartner, self).search(
            args=args, offset=offset, limit=limit, order=order, count=count)

    @api.model
    def create(self, vals):
        partner = super(ResPartner, self).create(vals)
        self._generate_associated_barcode(partner)
        self.check_designated_buyer(partner)
        return partner

    @api.multi
    def write(self, vals):
        asscociated_member_ids = self.filtered(
            lambda p: p.is_associated_people).ids
        res = super(ResPartner, self).write(vals)
        for partner in self:
            self._generate_associated_barcode(partner)
        # Recompute display_name if needed
        if ('barcode_base' in vals or 'is_member' in vals) and (
                not 'name' in vals):
            for partner in self:
                partner.name = partner.name

        if 'parent_id' in vals:
            # Update is_former_associated_people to true
            # if an associated member had been removed from its parent
            if not vals.get('parent_id'):
                for partner in self:
                    if partner.id in asscociated_member_ids:
                        partner.is_former_associated_people = True
        return res

    # Custom Section
    @api.model
    def check_designated_buyer(self, partner):
        company_id = self.env.user.company_id
        maximum_active_days = company_id.maximum_active_days
        today = fields.Date.from_string(fields.Date.today())
        if partner.is_designated_buyer:
            partner.deactivated_date = \
                today + timedelta(days=maximum_active_days)

    @api.model
    def _generate_associated_barcode(self, partner):
        barcode_rule_obj = self.env['barcode.rule']
        if partner.is_associated_people and not partner.barcode_rule_id\
                and not partner.barcode:
            # Generate Associated Barcode
            barcode_rule_id = barcode_rule_obj.search(
                [('for_associated_people', '=', True)], limit=1)
            if barcode_rule_id:
                partner.barcode_rule_id = barcode_rule_id.id
            partner.generate_base()
            partner.generate_barcode()

    @api.multi
    def send_welcome_email(self):
        mail_template = self.env.ref('coop_membership.welcome_email')
        if not mail_template:
            return False

        for partner in self:
            mail_template.send_mail(partner.id)
            partner.welcome_email = True
        return True

    # CRON section
    @api.model
    def update_is_unsubscribed_manually(self, partner_ids):
        """
        This is util function which call by Cron with passing partner_ids
        as arguments.
        It helps to test _compute_is_unsubscribed function easily 
        """
        partners = self.browse(partner_ids)
        partners._compute_is_unsubscribed()

    @api.model
    def update_is_unsubscribed(self):
        partners = self.search([])
        partners._compute_is_unsubscribed()

    @api.model
    def send_welcome_emails(self):
        partners = self.search([
            ('welcome_email', '=', False),
            ('is_worker_member', '=', True),
            ('is_unsubscribed', '=', False),
        ])
        partners.send_welcome_email()

    @api.model
    def deactivate_designated_buyer(self):
        partners = self.search([
            ('deactivated_date', '=', fields.Date.today())
        ])
        partners.write({
            'active': False
        })

    @api.model
    def cron_send_notify_mirror_children_email(self):
        today_dt = fields.Date.from_string(fields.Date.today())
        today_dt_last_18years = \
            today_dt - relativedelta(years=18) + relativedelta(weeks=2)
        today_dt_last_18years_tr = today_dt_last_18years.strftime("%Y-%m-%d")
        query = """
            SELECT id
            FROM res_partner 
            WHERE to_date(birthdate, 'YYYY-MM-DD') <= %s 
            AND parent_id IS NOT NULL 
            AND is_associated_people IS TRUE
            AND is_minor_child IS TRUE
        """
        self.env.cr.execute(
            query, (today_dt_last_18years_tr,)
        )
        result = self.env.cr.fetchall()
        if result:
            notify_email_template = self.env.ref(
                'coop_membership.notify_mirror_children_email')
            to_notify_member_ids = [item[0] for item in result]
            to_notify_members = self.browse(to_notify_member_ids)
            if notify_email_template:
                for member in to_notify_members:
                    notify_email_template.send_mail(member.id)

    @api.model
    def cron_update_mirror_children(self):
        today_dt = fields.Date.from_string(fields.Date.today())
        today_dt_last_18years = today_dt - relativedelta(years=18)
        today_dt_last_18years_tr = today_dt_last_18years.strftime("%Y-%m-%d")
        query = """
            SELECT id
            FROM res_partner 
            WHERE to_date(birthdate, 'YYYY-MM-DD') <= %s 
            AND parent_id IS NOT NULL 
            AND is_associated_people IS TRUE
            AND is_minor_child IS TRUE
            """
        self.env.cr.execute(
            query, (today_dt_last_18years_tr,)
        )
        result = self.env.cr.fetchall()
        if result:
            to_update_member_ids = [item[0] for item in result]
            to_update_members = self.browse(to_update_member_ids)
            to_update_members.write({
                'parent_id': False,
            })

            # Need to write again field `is_former_associated_people`
            to_update_members.write({
                'is_former_associated_people': False,
                'is_member': True,
            })

    # View section
    @api.multi
    def set_underclass_population(self):
        xml_id = self.env.ref('coop_membership.underclass_population_type').id
        for partner in self:
            partner.fundraising_partner_type_ids = [(4, xml_id)]

    @api.multi
    def remove_underclass_population(self):
        xml_id = self.env.ref('coop_membership.underclass_population_type').id
        for partner in self:
            partner.fundraising_partner_type_ids = [(3, xml_id)]

    @api.model
    def name_search(self, name, args=None, operator='ilike', limit=100):
        is_member_unsubscribed = self._context.get(
            'member_unsubscribed', False)
        if name.isdigit():
            domain = [('barcode_base', '=', name),
                      ('is_member', '=', True)]

            if is_member_unsubscribed:
                domain.append(('is_unsubscribed', '=', False))

            partners = self.search(domain, limit=limit)
            if partners:
                return partners.name_get()
        return super(ResPartner, self).name_search(
            name=name, args=args, operator=operator, limit=limit)

    @api.model
    def check_minor_child_birthdate(self, birthdate, is_minor_child):
        if birthdate and is_minor_child:
            birthdate = datetime.strptime(birthdate, "%Y-%m-%d").date()
            past_18_years_dt = date.today() - relativedelta(years=18)
            if birthdate < past_18_years_dt:
                raise ValidationError(_(
                    "Cette personne a plus de 18 ans et ne peux pas être "
                    "saisie comme un enfant mineur.")
                )

    @api.multi
    def name_get(self):
        res = []
        i = 0
        original_res = super(ResPartner, self).name_get()
        only_show_barcode_base = self._context.get(
            'only_show_barcode_base', False)

        for partner in self:
            original_value = original_res[i][1]
            name_get_values = (partner.id, original_value)
            if partner.is_member:
                name_get_values = (
                    partner.id,
                    '%s - %s' % (partner.barcode_base, original_value)
                )
            if only_show_barcode_base:
                name_get_values = (partner.id, str(partner.barcode_base))

            res.append(name_get_values)
            i += 1
        return res

    @api.multi
    def get_next_shift_date(self, start_date=None):
        '''
        @Function to get Next Shift Date of a member
        '''
        self.ensure_one()
        shift_reg = self.get_next_shift(start_date)
        if not shift_reg:
            return False, False

        next_shift_time = shift_reg.date_begin
        next_shift_date = False

        # Convert Next Shift Time into Local Time
        if next_shift_time:
            next_shift_time_obj = datetime.strptime(
                next_shift_time, '%Y-%m-%d %H:%M:%S')
            tz_name = self._context.get('tz', self.env.user.tz) or 'utc'
            utc_timestamp = pytz.utc.localize(
                next_shift_time_obj, is_dst=False)
            context_tz = pytz.timezone(tz_name)
            start_date_object_tz = utc_timestamp.astimezone(context_tz)
            next_shift_date = start_date_object_tz.strftime('%Y-%m-%d')

        return next_shift_time, next_shift_date

    @api.multi
    def get_next_shift(self, start_date=None):
        shift_registration_env = self.env['shift.registration']
        for partner in self:
            start_date = start_date or fields.Datetime.now()

            # Search for next shifts
            shift_regs = shift_registration_env.search([
                ('partner_id', '=', partner.id),
                ('template_created', '=', True),
                ('date_begin', '>=', start_date)
            ])

            if shift_regs:
                # Sorting found shift
                shift_regs = shift_regs.sorted(
                    key=lambda shift: shift.date_begin)
                return shift_regs[0]

        return False

    @api.multi
    def _mass_change_team(self):
        active_ids = self._context.get('active_ids', [])
        partner_ids = active_ids
        if partner_ids:
            partner_id = partner_ids[0]
            partner_ids.remove(partner_ids[0])
            changed_team_ids = []
            return {
                'name': _('Change Team'),
                'type': 'ir.actions.act_window',
                'res_model': 'shift.change.team',
                'view_type': 'form',
                'target': 'new',
                'view_mode': 'form',
                'context': {'default_partner_id': partner_id,
                            'partner_ids': partner_ids,
                            'changed_team_ids': changed_team_ids,
                            },
            }

    @api.multi
    def _update_when_number_of_shares_reaches_0(self):
        self.ensure_one()
        # only take into count member that already
        # has partner_owned_share before
        invoice_states = []
        for partner_share in self.partner_owned_share_ids:
            invoice_states += [
                invoice.state in ['open', 'paid', 'cancel'] for
                invoice in partner_share.related_invoice_ids
            ]
        # all invoice states != 'draft'
        invoice_states = all(invoice_states)
        if self.partner_owned_share_ids \
            and self.partner_owned_share_ids[0].related_invoice_ids \
                and invoice_states and self.total_partner_owned_share == 0:

            # Set date and for shift template
            for tmpl_reg in self.tmpl_reg_line_ids:
                if not tmpl_reg.date_end or tmpl_reg.date_end >\
                        fields.Datetime.now():
                    tmpl_reg.write({
                        'date_end': fields.Datetime.now()
                    })

            # Set date begin for shift ticket
            for reg in self.registration_ids:
                if reg.date_begin > fields.Datetime.now():
                    reg.write({
                        'date_begin': fields.Datetime.now()
                    })

            # Update Mailling opt out
            """
            # issue: disappear property_account_payable/recievable_id
            # when creating a child partner 
            # (open wizard to add child contact)
            when creating a associate people from contact tab,
            the total_partner_owned_share of new partner is zero,
            so if we don't check partner_owned_share_ids,
            this opt_out is set for new partner also
            and somehow, property_account are disappeared on parent partner.
            => add a check partner_owned_shared_ids to only apply for partner
            which already has partner_owned_share
            """
            self.write({
                'opt_out': True
            })
        return True

    @api.multi
    def generate_pdf(self, report_name):
        context = dict(self._context or {})
        active_ids = self.ids
        context.update({
            'active_model': self._name,
            'active_ids': active_ids,
        })
        return self.env['report'].with_context(context).\
            get_pdf(self, report_name)

    @api.multi
    def attach_report_in_mail(self):
        self.ensure_one()
        report_name = 'coop_membership.member_contract_template'
        report = self.generate_pdf(report_name)
        encoded_report = base64.encodestring(report)
        filename = 'Member Contract'

        # create the new ir_attachment
        attachment_value = {
            'name': filename,
            'res_name': filename,
            'res_model': 'res.partner',
            'datas': encoded_report,
            'datas_fname': filename + '.pdf',
        }
        new_attachment = self.env['ir.attachment'].create(attachment_value)
        return new_attachment

    def fields_view_get(self, cr, uid, view_id=None, view_type='form',
                        context=None, toolbar=False, submenu=False):
        if context is None:
            context = {}

        res = super(ResPartner, self).fields_view_get(
            cr, uid,
            view_id=view_id,
            view_type=view_type,
            context=context,
            toolbar=toolbar,
            submenu=submenu)
        # Read only field contact base specific groups
        doc = etree.fromstring(res['arch'])
        if uid != SUPERUSER_ID:
            lecture_group = self.user_has_groups(
                cr, uid,
                'coop_membership.group_membership_bdm_lecture')
            writer_group = self.user_has_groups(
                cr, uid,
                'coop_membership.group_membership_access_edit')
            if view_type == 'form':
                if lecture_group and not writer_group:
                    model_data_obj = self.pool['ir.model.data']
                    shift_ext_from_partner_id = model_data_obj. \
                        get_object_reference(
                        cr, uid,
                        'coop_shift',
                        'act_shift_registration_from_partner')[1]
                    shift_ext_from_partner_tree_id = model_data_obj. \
                        get_object_reference(
                        cr, uid,
                        'coop_shift',
                        'act_shift_registration_from_partner_tree_mode')[1]

                    tpl_reg_line_fr_partner_id = model_data_obj. \
                        get_object_reference(
                        cr, uid,
                        'coop_shift',
                        'act_template_registration_line_from_partner')[1]
                    tpl_reg_line_fr_partner_tree_id = model_data_obj. \
                        get_object_reference(
                        cr, uid,
                        'coop_shift',
                        'act_template_registration_line_from_partner_tree_mode')[1]

                    for node in doc.xpath("//button"):
                        if node.get('name') == str(shift_ext_from_partner_id):
                            node.set(
                                'name',
                                str(shift_ext_from_partner_tree_id))
                        if node.get('name') == str(tpl_reg_line_fr_partner_id):
                            node.set(
                                'name',
                                str(tpl_reg_line_fr_partner_tree_id))
        access_inform = self.user_has_groups(
            cr, uid,
            'coop_membership.coop_group_access_res_partner_inform'
        )
        if not access_inform:
            node = doc.xpath("//field[@name='inform_ids']")
            options = {
                'no_create': True,
                'no_quick_create': True,
                'no_create_edit': True
            }
            if node:
                node[0].set("options", repr(options))
                setup_modifiers(node[0], res['fields']['inform_ids'])

        edit_contact_us_message = self.user_has_groups(
            cr, uid, 'coop_membership.group_edit_contact_messeage')
        if not edit_contact_us_message:
            node = doc.xpath("//field[@name='contact_us_message']")
            if node:
                node[0].set("readonly", "1")
                setup_modifiers(node[0], res['fields']['contact_us_message'])
        can_modify_partner_photo = self.user_has_groups(
            cr, uid,
            'coop_membership.coop_group_access_res_partner_image'
        )
        if can_modify_partner_photo:
            node = doc.xpath("//field[@name='image']")
            if node:
                node[0].set("readonly", "0")
                setup_modifiers(node[0], res['fields']['image'])

        res['arch'] = etree.tostring(doc)
        return res

    @api.multi
    def update_shift_type(self):
        partners = self.ids
        num_partner_per_job = 100
        splited_partner_list = \
            [partners[i: i + num_partner_per_job]
             for i in range(0, len(partners), num_partner_per_job)]
        # Prepare session for job
        session = ConnectorSession(self._cr, self._uid)
        # Create jobs
        for partner_list in splited_partner_list:
            update_shift_type_res_partner_session_job.delay(
                session, 'res.partner', partner_list)
        return True

    @api.multi
    def create_job_to_compute_current_template(self):
        partners = self.ids
        num_partner_per_job = 100
        splited_partner_list = \
            [partners[i: i + num_partner_per_job]
             for i in range(0, len(partners), num_partner_per_job)]
        # Prepare session for job
        session = ConnectorSession(self._cr, self._uid)
        # Create jobs
        for partner_list in splited_partner_list:
            update_member_current_template_name.delay(
                session, 'res.partner', partner_list)
        return True
Exemple #25
0
class sohovet_vaccine_reminder_wizard(models.TransientModel):
    _name = 'sohovet.vaccine.reminder.wizard'

    @api.multi
    def _get_init_date(self):
        now = datetime.now()
        day = 1
        month = now.month
        year = now.year
        return datetime(year, month, day)

    @api.multi
    def _get_end_date(self):
        now = datetime.now()
        month = now.month
        year = now.year
        day = calendar.monthrange(year, month)[1]
        return datetime(year, month, day)

    @api.multi
    def _get_default_last_reminder_min_date(self):
        now = datetime.now()
        day = 1
        month = now.month - 1
        year = now.year
        if month <= 0:
            month = month + 12
            year = year - 1
        return datetime(year, month, day)

    @api.multi
    def _get_default_last_reminder_max_date(self):
        now = datetime.now()
        month = now.month - 1
        year = now.year
        if month <= 0:
            month += 12
            year -= 1
        day = calendar.monthrange(year, month)[1]
        return datetime(year, month, day)

    @api.multi
    def _is_updated_48h(self):
        dt_format = '%Y-%m-%d %H:%M:%S'

        config = self.env['ir.config_parameter']
        date_str = config.get_param('connector.last_update')

        if not date_str:
            return False

        last_date = datetime.strptime(date_str, dt_format)
        current_date = datetime.utcnow()

        return current_date - last_date < timedelta(hours=48)

    init_date = fields.Date('Fecha inicial', required=True, default=_get_init_date)
    end_date = fields.Date('Fecha final', required=True, default=_get_end_date)
    type = fields.Selection([('first', 'Primer recordatorio'), ('other', 'Recordatorios de repesca')],
                            'Tipo de recordatorios', default='first', required=True)
    max_sent_reminders = fields.Integer('Número máximo de recordatorios anteriores', default=1, required=True)
    last_reminder_min_date = fields.Date('Fecha mínima del último recordatorio', default=_get_default_last_reminder_min_date, required=True)
    last_reminder_max_date = fields.Date('Fecha máxima del último recordatorio', default=_get_default_last_reminder_max_date, required=True)
    updated_48h = fields.Boolean('Sincronizados en las últimas 48h.', required=True, readonly=True, default=_is_updated_48h)

    @api.multi
    def generate_reminders(self):
        # Borrar recordatorios en borrador
        draft_reminders = self.env['sohovet.vaccine.reminder'].search([('state', 'in', ['draft', 'incomplete'])])
        for reminder in draft_reminders:
            reminder.unlink()
            # reminder.state = 'cancel'

        # Generar recordatorios nuevos
        if self.type == 'first':
            search_data = [
                ('animal_active', '=', True),
                ('partner_active', '=', True),
                ('animal_alive', '=', True),
                ('next_type_id', '!=', False),
                ('next_vaccine', '=', False),
                ('date_next_computed', '>=', self.init_date),
                ('date_next_computed', '<=', self.end_date),
                ('num_sent_reminders', '=', 0),
            ]
        elif self.type == 'other':
            search_data = [
                ('animal_active', '=', True),
                ('partner_active', '=', True),
                ('animal_alive', '=', True),
                ('next_type_id', '!=', False),
                ('next_vaccine', '=', False),
                ('last_reminder_date', '>=', self.last_reminder_min_date),
                ('last_reminder_date', '<=', self.last_reminder_max_date),
                ('num_sent_reminders', '>', 0),
                ('num_sent_reminders', '<=', self.max_sent_reminders),
            ]

        vaccines = self.env['sohovet.vaccine'].search(search_data)

        ## DOUBLE CHECK!!
        if vaccines:
            quick_updater = self.env['sohovet.connector.quick.update'].create({})
            quick_updater.update_partners([vaccine.animal_id.partner_id for vaccine in vaccines])
            quick_updater.update_animals([vaccine.animal_id for vaccine in vaccines])
            quick_updater.update_vaccines([vaccine for vaccine in vaccines])

            vaccines = self.env['sohovet.vaccine'].search(search_data)
        ###########

        prop = {}
        for vaccine in vaccines:
            # if not vaccine.animal_id.partner_id.mobile:
            #     continue
            id_partner = vaccine.animal_id.partner_id.id
            if id_partner in prop:
                prop[id_partner].append(vaccine)
            else:
                prop[id_partner] = [vaccine]

        for id_partner in prop:
            reminder_data = {
                'type': self.type,
                'partner_id': id_partner,
                'vaccine_ids': [(6, 0, [vaccine.id for vaccine in prop[id_partner]])],
            }
            self.env['sohovet.vaccine.reminder'].create(reminder_data)

        return {
            'type': 'ir.actions.client',
            'tag': 'reload',
        }
Exemple #26
0
class ResInvestConstruction(LogCommon, models.Model):
    _inherit = 'res.invest.construction'

    code = fields.Char(
        readonly=True,
        default='/',
        copy=False,
    )
    state = fields.Selection(
        [('draft', 'Draft'),
         ('submit', 'Submitted'),
         ('unapprove', 'Un-Approved'),
         ('approve', 'Approved'),
         ('reject', 'Rejected'),
         ('delete', 'Deleted'),
         ('cancel', 'Cancelled'),
         ('close', 'Closed'),
         ],
        string='Status',
        required=True,
        readonly=True,
        copy=False,
        default='draft',
    )
    month_duration = fields.Integer(
        string='Duration (months)',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
        copy=False,
    )
    date_start = fields.Date(
        string='Start Date',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
        copy=False,
    )
    date_end = fields.Date(
        string='End Date',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
        copy=False,
    )
    pm_employee_id = fields.Many2one(
        'hr.employee',
        string='Project Manager',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)]},
    )
    pm_section_id = fields.Many2one(
        'res.section',
        string='Project Manager Section',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)]},
    )
    org_id = fields.Many2one(
        'res.org',
        string='Org',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)]},
        help="Org where this construction project belong to. "
        "Use default as PM's org, but changable."
    )
    mission_id = fields.Many2one(
        'res.mission',
        string='Core Mission',
        required=True,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)]},
    )
    amount_budget_plan = fields.Float(
        string='Planned Budget',
        compute='_compute_amount_budget_plan',
        readonly=True,
    )
    amount_budget_approve = fields.Float(
        string='Approved Budget',
        default=0.0,
        readonly=True,
        states={'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
        write=['pabi_base.group_cooperate_budget'],  # Only Corp can edit
    )
    amount_phase_approve = fields.Float(
        string='Approved Budget (Phases)',
        compute='_compute_amount_phase_approve',
        store=True,
    )
    operation_area = fields.Char(
        string='Operation Area',
    )
    date_expansion = fields.Date(
        string='Expansion Date',
    )
    approval_info = fields.Text(
        string='Approval Info',
    )
    project_readiness = fields.Text(
        string='Project Readiness',
    )
    reason = fields.Text(
        string='Reason',
    )
    expected_result = fields.Text(
        string='Expected Result',
    )
    budget_plan_ids = fields.One2many(
        'res.invest.construction.budget.plan',
        'invest_construction_id',
        string='Budget Planning',
    )
    phase_ids = fields.One2many(
        domain=['|', ('active', '=', True), ('active', '=', False)],
    )
    _sql_constraints = [
        ('number_uniq', 'unique(code)',
         'Constuction Project Code must be unique!'),
    ]

    @api.multi
    @api.constrains('budget_plan_ids')
    def _check_fiscalyear_unique(self):
        for rec in self:
            fiscalyear_ids = [x.fiscalyear_id.id for x in rec.budget_plan_ids]
            for x in fiscalyear_ids:
                if fiscalyear_ids.count(x) > 1:
                    raise ValidationError(_('Duplicate fiscalyear plan'))

    @api.model
    def _check_cooperate_access(self):
        if not self.env.user.has_group('pabi_base.group_cooperate_budget'):
            raise ValidationError(
                _('Only Cooperate Budget user is allowed!'))
        return True

    @api.multi
    @api.depends('phase_ids.amount_phase_approve')
    def _compute_amount_phase_approve(self):
        for rec in self:
            amount_total = sum([x.amount_phase_approve for x in rec.phase_ids])
            if amount_total and float_compare(amount_total,
                                              rec.amount_budget_approve,
                                              precision_digits=2) != 0:
                raise ValidationError(
                    _('Phases Approved Amount != Project Approved Amount'))
            rec.amount_phase_approve = amount_total

    @api.multi
    @api.constrains('date_expansion', 'date_start', 'date_end')
    def _check_date(self):
        for rec in self:
            # Date End must >= Date Start
            if rec.date_end and rec.date_start and \
                    rec.date_end < rec.date_start:
                raise ValidationError(
                    _('End Date must start after than Start Date!'))
            # Expansion Date must >= End date
            if rec.date_expansion and rec.date_end and \
                    rec.date_expansion < rec.date_end:
                raise ValidationError(
                    _('Expansion Date must start after than End Date!'))

    @api.multi
    @api.depends('budget_plan_ids.amount_plan')
    def _compute_amount_budget_plan(self):
        for rec in self:
            rec.amount_budget_plan = \
                sum([x.amount_plan for x in rec.budget_plan_ids])

    @api.model
    def create(self, vals):
        if vals.get('code', '/') == '/':
            fiscalyear_id = self.env['account.fiscalyear'].find()
            vals['code'] = self.env['ir.sequence'].\
                with_context(fiscalyear_id=fiscalyear_id).\
                next_by_code('invest.construction')
        return super(ResInvestConstruction, self).create(vals)

    @api.onchange('pm_employee_id')
    def _onchange_user_id(self):
        employee = self.pm_employee_id
        self.pm_section_id = employee.section_id
        self.org_id = employee.org_id

    @api.onchange('month_duration', 'date_start', 'date_end')
    def _onchange_date(self):
        if not self.month_duration or not self.date_start:
            self.date_end = False
        else:
            date_start = datetime.strptime(self.date_start, '%Y-%m-%d').date()
            date_end = date_start + relativedelta(months=self.month_duration)
            self.date_end = date_end.strftime('%Y-%m-%d')
        self._prepare_budget_plan_line(self.date_start, self.date_end)

    @api.model
    def _prepare_budget_plan_line(self, date_start, date_end):
        self.budget_plan_ids = False
        Fiscal = self.env['account.fiscalyear']
        Plan = self.env['res.invest.construction.budget.plan']
        if date_start and date_end:
            fiscal_start_id = Fiscal.find(date_start)
            fiscal_end_id = Fiscal.find(date_end)
            fiscal_start = Fiscal.browse(fiscal_start_id)
            fiscal_end = Fiscal.browse(fiscal_end_id)
            if not fiscal_start.name.isdigit():
                raise ValidationError(
                    _("Config: Fiscalyear name not represent a year integer!"))
            fiscal_year = int(fiscal_start.name)
            while fiscal_year <= int(fiscal_end.name):
                fiscal = Fiscal.search([('name', '=', str(fiscal_year))])
                if fiscal:
                    plan = Plan.new()
                    plan.fiscalyear_id = fiscal
                    plan.amount_plan = 0.0
                    self.budget_plan_ids += plan
                fiscal_year += 1
        return True

    @api.multi
    def action_create_phase(self):
        for rec in self:
            if rec.phase_ids:
                continue
            phases = []
            i = 1
            for phase in sorted(CONSTRUCTION_PHASE.items()):
                phases.append((0, 0, {'sequence': i, 'phase': phase[0]}))
                i += 1
            rec.write({'phase_ids': phases})

    # Statuses
    @api.multi
    def action_submit(self):
        self.write({'state': 'submit'})

    @api.multi
    def action_approve(self):
        self._check_cooperate_access()
        self.action_create_phase()
        self.write({'state': 'approve'})

    @api.multi
    def action_unapprove(self):
        # Unapprove all phases, only those in Approved state
        for rec in self:
            rec.phase_ids.filtered(
                lambda l: l.state == 'approve').action_unapprove()
        self.write({'state': 'unapprove'})

    @api.multi
    def action_reject(self):
        self.write({'state': 'reject'})

    @api.multi
    def action_delete(self):
        self.write({'state': 'delete'})

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

    @api.multi
    def action_close(self):
        self.write({'state': 'close'})

    @api.multi
    def action_draft(self):
        self.write({'state': 'draft'})
class assets_report_registry(models.TransientModel):
    _name = 'assets.report.registry'

    date_start = fields.Date(string='Asset Start Date')
    date_end = fields.Date(string='Asset End Date')

    category_id = fields.Many2many('account.asset.category',
                                   string='Asset Category')
    asset_id = fields.Many2many('account.asset.asset', string='Asset Name')

    # v7
    def report_registry_print(self, cr, uid, ids, context=None):
        """
        Avvio la stampa verso il report in base alla scelta dell'utente nel Wizard

        :param cr:
        :param uid:
        :param ids:
        :param context:
        :return:
        """

        # Recupera le informazioni del wizard
        wizard = self.browse(cr, uid, ids[0], context=context)

        # Recupero i recordset
        search_obj = self.pool['account.asset.depreciation.line.fiscal']

        search_domain = []
        # Pre ricerca condizionale
        if wizard.category_id:
            search_domain += [
                ('asset_id.category_id', 'in',
                 [category.id for category in wizard.category_id])
            ]
        if wizard.asset_id:
            search_domain += [('asset_id', 'in',
                               [asset.id for asset in wizard.asset_id])]
        if wizard.date_start and wizard.date_end:
            search_domain += [('line_date', '>=', wizard.date_start),
                              ('line_date', '<=', wizard.date_end)]
        elif wizard.date_start:
            search_domain += [('line_date', '>=', wizard.date_start)]
        elif wizard.date_end:
            search_domain += [('line_date', '<=', wizard.date_end)]

        # Effettuo una ricerca in base alla selezione dell'utente
        search_ids = search_obj.search(cr, uid, search_domain)

        if not search_ids:
            raise UserError(_('No documents found in the current selection'))
        # else

        unique_asset_id = []
        # Genero una lista degli ID univoci degli asset presenti nella ricerca
        for single_id in search_obj.browse(cr,
                                           uid,
                                           search_ids,
                                           context=context):
            if not single_id['asset_id'].id in unique_asset_id:
                unique_asset_id.append(single_id['asset_id'].id)

        datas_form = {}
        datas_form['asset_ids'] = unique_asset_id
        datas_form['date_start'] = wizard.date_start
        datas_form['date_end'] = wizard.date_end

        report_name = 'l10n_it_assets_report.report_assets_report_registry'

        datas = {}
        datas = {
            'ids': search_ids,
            'model': 'account.asset.depreciation.line.fiscal',
            'form': datas_form,
        }

        # Richiamo le azioni sul Report (Parser)
        return self.pool['report'].get_action(cr,
                                              uid, [],
                                              report_name,
                                              data=datas,
                                              context=context)
Exemple #28
0
class RestInvestConstructionPhase(LogCommon, models.Model):
    _inherit = 'res.invest.construction.phase'

    active = fields.Boolean(
        string='Active',
        compute='_compute_active',
        store=True,
        help="Phase is activated only when approved",
    )
    code = fields.Char(
        readonly=True,
        default='/',
        copy=False,
    )
    org_id = fields.Many2one(
        'res.org',
        string='Org',
        related='invest_construction_id.org_id',
        store=True,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)]},
    )
    state = fields.Selection(
        [('draft', 'Draft'),
         ('submit', 'Submitted'),
         ('unapprove', 'Un-Approved'),
         ('approve', 'Approved'),
         ('reject', 'Rejected'),
         ('delete', 'Deleted'),
         ('cancel', 'Cancelled'),
         ('close', 'Closed'),
         ],
        string='Status',
        readonly=True,
        required=True,
        copy=False,
        default='draft',
    )
    amount_phase_approve = fields.Float(
        string='Approved Budget (Phase)',
        default=0.0,
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
    )
    amount_phase_plan = fields.Float(
        string='Planned Budget (Phase)',
        compute='_compute_amount_phase_plan',
        readonly=True,
    )
    amount_phase_diff = fields.Float(
        string='Unplanned Budget (Phase)',
        compute='_compute_amount_phase_plan',
        readonly=True,
    )
    month_duration = fields.Integer(
        string='Duration (months)',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
    )
    date_start = fields.Date(
        string='Start Date',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
    )
    date_end = fields.Date(
        string='End Date',
        readonly=True,
        states={'draft': [('readonly', False)],
                'submit': [('readonly', False)],
                'unapprove': [('readonly', False)]},
    )
    date_expansion = fields.Date(
        string='Date Expansion',
    )
    contract_day_duration = fields.Integer(
        string='Contract Duration (days)',
        readonly=True,
        states={'approve': [('readonly', False)], },
    )
    contract_date_start = fields.Date(
        string='Contract Start Date',
        readonly=True,
        states={'approve': [('readonly', False)], },
    )
    contract_date_end = fields.Date(
        string='Contract End Date',
        readonly=True,
        states={'approve': [('readonly', False)], },
    )
    contract_ids = fields.Many2many(
        'purchase.contract',
        string='Contract Number',
        readonly=True,
        states={'approve': [('readonly', False)], },
    )
    phase_plan_ids = fields.One2many(
        'res.invest.construction.phase.plan',
        'invest_construction_phase_id',
        string='Budget Planning (Phase)',
    )
    fiscalyear_ids = fields.Many2many(
        'account.fiscalyear',
        'construction_phase_fiscalyear_rel', 'phase_id', 'fiscalyear_id',
        string='Related Fiscal Years',
        compute='_compute_fiscalyear_ids',
        store=True,
        help="All related fiscal years for this phases"
    )
    budget_count = fields.Integer(
        string='Budget Control Count',
        compute='_compute_budget_count',
    )
    budget_to_sync_count = fields.Integer(
        string='Budget Need Sync Count',
        compute='_compute_budget_to_sync_count',
    )
    to_sync = fields.Boolean(
        string='To Sync',
        compute='_compute_budget_to_sync_count',
    )
    sync_ids = fields.One2many(
        'res.invest.construction.phase.sync',
        'phase_id',
        string='Sync History',
        copy=False,
    )
    summary_ids = fields.One2many(
        'invest.construction.phase.summary',
        'phase_id',
        string='Phase Summary',
        readonly=True,
    )
    _sql_constraints = [
        ('number_uniq', 'unique(code)',
         'Constuction Phase Code must be unique!'),
    ]

    @api.multi
    @api.constrains('phase_plan_ids')
    def _check_fiscalyear_unique(self):
        for rec in self:
            period_ids = [x.calendar_period_id.id for x in rec.phase_plan_ids]
            for x in period_ids:
                if period_ids.count(x) > 1:
                    raise ValidationError(
                        _('Duplicate period in budget plan!'))

    @api.multi
    @api.constrains('date_expansion', 'date_start', 'date_end')
    def _check_date(self):
        for rec in self:
            # Date End must >= Date Start
            if rec.date_end and rec.date_start and \
                    rec.date_end < rec.date_start:
                raise ValidationError(
                    _('End Date must start after than Start Date!'))
            # Expansion Date must >= End date
            if rec.date_expansion and rec.date_end and \
                    rec.date_expansion < rec.date_end:
                raise ValidationError(
                    _('Expansion Date must start after than End Date!'))
            # -- Check with Project -- #
            c = rec.invest_construction_id
            # Date Start must >= Project's Date start
            if rec.date_start and c.date_start and \
                    rec.date_start < c.date_start:
                raise ValidationError(
                    _('Start Date must start after than Project Start Date!'))
            # Date End must <= Project's Date End/Expansion
            if rec.date_end and (c.date_expansion or c.date_end) and \
                    rec.date_end > (c.date_expansion or c.date_end):
                raise ValidationError(
                    _('End Date must end before Project End Date!'))
            # Date Expansion must <= Project's Date End/Expansion
            if rec.date_expansion and (c.date_expansion or c.date_end) and \
                    rec.date_expansion > (c.date_expansion or c.date_end):
                raise ValidationError(
                    _('Expansion Date must end before '
                      'Project Expansion Date!'))

    @api.model
    def _get_changed_plan_fiscalyear(self, vals):
        # For changes, find the related fiscalyear_ids and update the sync
        PhasePlan = self.env['res.invest.construction.phase.plan']
        # Update (1)
        changed_plans = filter(lambda x: x[0] == 1,
                               vals.get('phase_plan_ids'))
        plan_ids = map(lambda x: x[1], changed_plans)
        plans = PhasePlan.browse(plan_ids)
        year_ids = [x.fiscalyear_id.id for x in plans]
        # Create (0)
        changed_plans = filter(lambda x: x[0] == 0 and x[1] is False,
                               vals.get('phase_plan_ids'))
        year_ids += map(lambda x: x[2].get('fiscalyear_id'), changed_plans)
        return year_ids

    @api.multi
    def write(self, vals):
        if vals.get('phase_plan_ids', False):
            year_ids = self._get_changed_plan_fiscalyear(vals)
            for phase in self:
                phase.sync_ids.filtered(lambda l: l.fiscalyear_id.id
                                        in year_ids).write({'synced': False})
        return super(RestInvestConstructionPhase, self).write(vals)

    @api.multi
    @api.depends('state')
    def _compute_active(self):
        for rec in self:
            rec.active = rec.state == 'approve'

    @api.model
    def find_active_construction_budget(self, fiscalyear_ids, org_ids):
        budgets = self.env['account.budget'].search([
            ('chart_view', '=', 'invest_construction'),
            ('active', '=', True),
            ('fiscalyear_id', 'in', fiscalyear_ids),
            ('org_id', 'in', org_ids)])
        return budgets

    @api.multi
    @api.depends()
    def _compute_budget_count(self):
        for rec in self:
            # Show all budget control with the same org and same fiscalyear
            budgets = self.find_active_construction_budget(
                rec.fiscalyear_ids.ids, [rec.org_id.id])
            rec.budget_count = len(budgets)

    @api.multi
    @api.depends('sync_ids')
    def _compute_budget_to_sync_count(self):
        for rec in self:
            to_sync_fiscals = rec.sync_ids.filtered(
                lambda l: not l.synced).mapped('fiscalyear_id')
            budgets = self.find_active_construction_budget(
                to_sync_fiscals.ids, [rec.org_id.id])
            rec.budget_to_sync_count = len(budgets)
            rec.to_sync = len(budgets) > 0 and True or False

    @api.multi
    @api.depends('phase_plan_ids.amount_plan')
    def _compute_amount_phase_plan(self):
        for rec in self:
            rec.amount_phase_plan = \
                sum([x.amount_plan for x in rec.phase_plan_ids])
            rec.amount_phase_diff = \
                rec.amount_phase_approve - rec.amount_phase_plan

    @api.model
    def create(self, vals):
        if vals.get('code', '/') == '/':
            prefix = 'N/A-'
            if vals.get('invest_construction_id', False):
                project = self.env['res.invest.construction'].\
                    browse(vals.get('invest_construction_id'))
                prefix = str(project.code) + '-'
            vals['code'] = prefix + '{:02d}'.format(vals.get('sequence', 0))
        return super(RestInvestConstructionPhase, self).create(vals)

    @api.onchange('month_duration', 'date_start', 'date_end')
    def _onchange_date(self):
        if not self.month_duration or not self.date_start:
            self.date_end = False
        else:
            date_start = datetime.strptime(self.date_start, '%Y-%m-%d').date()
            date_end = date_start + relativedelta(months=self.month_duration)
            self.date_end = date_end.strftime('%Y-%m-%d')
        self._prepare_phase_plan_line(self.date_start, self.date_end)

    @api.onchange('contract_day_duration', 'contract_date_start',
                  'contract_date_end')
    def _onchange_contract_date(self):
        if not self.contract_day_duration or not self.contract_date_start:
            self.contract_date_end = False
        else:
            date_start = \
                datetime.strptime(self.contract_date_start, '%Y-%m-%d').date()
            date_end = \
                date_start + relativedelta(days=self.contract_day_duration)
            self.contract_date_end = date_end.strftime('%Y-%m-%d')

    @api.model
    def _prepare_phase_plan_line(self, date_start, date_end):
        self.phase_plan_ids = False
        Period = self.env['account.period']
        Plan = self.env['res.invest.construction.phase.plan']
        date = date_start
        if date and date_end:
            while date <= date_end:
                period = Period.find(date)
                plan = Plan.new()
                plan.calendar_period_id = period.id
                plan.amount_plan = 0.0
                self.phase_plan_ids += plan
                next_period = Period.next(period, 1)
                date = next_period.date_start
                if not next_period:
                    raise ValidationError(
                        _('No period configured for the target end date'))
        return True

    @api.multi
    @api.depends('phase_plan_ids.fiscalyear_id')
    def _compute_fiscalyear_ids(self):
        for phase in self:
            fiscalyear_ids = [x.fiscalyear_id.id
                              for x in phase.phase_plan_ids]
            phase.fiscalyear_ids = list(set(fiscalyear_ids))

    @api.model
    def _prepare_mo_dict(self, fiscalyear, prefix):
        """ {1: 'm10', ..., 12: 'm9'}, {'m1': False, ..., 'm12': False} """
        month = int(fiscalyear.date_start[5:7])
        mo_dict = {}
        for i in range(12):
            mo_dict.update({month: prefix + str(i + 1)})
            month += 1
            if month > 12:
                month = 1
        vals = dict([(v, False) for v in mo_dict.values()])
        return (mo_dict, vals)

    @api.multi
    def sync_phase_to_budget_line(self, fiscalyear_ids=False):
        """
        fiscalyear_ids specify which year to sync, otherwise, all sync.
        only sync if synced=False
        """
        for phase in self:
            # Find phase with vaild sync history (has been pulled before)
            phase_syncs = not fiscalyear_ids and phase.sync_ids or \
                phase.sync_ids.filtered(lambda l: l.fiscalyear_id.id
                                        in fiscalyear_ids)
            if not phase_syncs:
                continue
            for sync in phase_syncs:
                # No valid budate line reference, or already synced, ignore it
                # (need to pull from budget control first)
                if not sync.sync_budget_line_id or sync.synced:
                    continue
                # Prepare update dict
                fiscalyear = sync.fiscalyear_id
                mo_dict, vals = self._prepare_mo_dict(fiscalyear, 'm')
                # Update it
                for plan in phase.phase_plan_ids.filtered(
                        lambda l: l.fiscalyear_id.id == fiscalyear.id):
                    period = plan.calendar_period_id
                    month = int(period.date_start[5:7])
                    vals[mo_dict[month]] = plan.amount_plan
                sync.sync_budget_line_id.write(vals)
                # Mark synced
                sync.write({'synced': True,
                            'last_sync': fields.Datetime.now()})
        return True

    @api.multi
    def action_sync_phase_to_budget_line(self):
        return self.sync_phase_to_budget_line(fiscalyear_ids=False)  # do all

    @api.multi
    def _set_amount_plan_init(self):
        for phase in self:
            for plan in phase.phase_plan_ids:
                if not plan.amount_plan_init:
                    plan.amount_plan_init = plan.amount_plan

    @api.multi
    def _check_amount_plan_approve(self):
        for phase in self:
            if float_compare(phase.amount_phase_plan,
                             phase.amount_phase_approve,
                             precision_digits=2) != 0:
                raise ValidationError(
                    _('Planned amount not equal to approved amount!'))

    @api.multi
    def _create_phase_sync(self):
        # Create phase sync of all fiscalyear_ids (if not exists)
        for phase in self:
            syncs = []
            exist_fiscal_ids = [x.fiscalyear_id.id for x in phase.sync_ids]
            for fiscalyear in phase.fiscalyear_ids:
                # Not already exists, create it.
                if fiscalyear.id not in exist_fiscal_ids:
                    sync = {'fiscalyear_id': fiscalyear.id,
                            'last_sync': False,
                            'synced': False, }
                    syncs.append((0, 0, sync))
            phase.write({'sync_ids': syncs})

    @api.multi
    def action_open_budget_control(self):
        self.ensure_one()
        self.env['res.invest.construction']._check_cooperate_access()
        action = self.env.ref('pabi_chartfield.'
                              'act_account_budget_view_invest_construction')
        result = action.read()[0]
        budgets = self.find_active_construction_budget(self.fiscalyear_ids.ids,
                                                       [self.org_id.id])
        dom = [('id', 'in', budgets.ids)]
        result.update({'domain': dom})
        return result

    @api.multi
    def action_open_to_sync_budget_control(self):
        self.ensure_one()
        self.env['res.invest.construction']._check_cooperate_access()
        action = self.env.ref('pabi_chartfield.'
                              'act_account_budget_view_invest_construction')
        result = action.read()[0]
        to_sync_fiscals = self.sync_ids.filtered(
            lambda l: not l.synced).mapped('fiscalyear_id')
        budgets = self.find_active_construction_budget(to_sync_fiscals.ids,
                                                       [self.org_id.id])
        dom = [('id', 'in', budgets.ids)]
        result.update({'domain': dom})
        return result

    # Statuses
    @api.multi
    def action_submit(self):
        self.write({'state': 'submit'})

    @api.multi
    def action_approve(self):
        self.env['res.invest.construction']._check_cooperate_access()
        self._check_amount_plan_approve()
        self._set_amount_plan_init()
        self._create_phase_sync()
        self.write({'state': 'approve'})

    @api.multi
    def action_unapprove(self):
        self.write({'state': 'unapprove'})

    @api.multi
    def action_reject(self):
        self.write({'state': 'reject'})

    @api.multi
    def action_delete(self):
        self.write({'state': 'delete'})

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

    @api.multi
    def action_close(self):
        self.write({'state': 'close'})

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

    @api.multi
    @api.constrains('sync_ids', 'state')
    def _trigger_auto_sync(self):
        for phase in self:
            to_sync_fiscals = phase.sync_ids.filtered(
                lambda l: not l.synced).mapped('fiscalyear_id')
            budgets = self.find_active_construction_budget(to_sync_fiscals.ids,
                                                           [phase.org_id.id])
            for budget in budgets:
                if budget.construction_auto_sync:
                    budget.with_context(
                        phase=phase.id).sync_budget_invest_construction()
Exemple #29
0
class bank_deposit(models.Model):
    _name = 'bank.deposit'

    name = fields.Char(string='Number')
    partner = fields.Many2one(comodel_name='res.partner', string='Partner')
    date = fields.Date(string='Open Date', default=fields.Date.today())
    last_calculate = fields.Date(string='Last Calculate', default=fields.Date.today())
    rate = fields.Many2one(comodel_name='bank.deposit.rate',
                           string='Interest Rate')
    amount = fields.Float(string='Actual Amount',
                          digits=dp.get_precision('Account'))
    move_ids = fields.One2many(comodel_name='bank.deposit.move',
                                string='Money Moves',
                                inverse_name='deposit_id')
    users = fields.Many2many(
        string='Users', comodel_name='res.users',
        relation='bank_deposit_user_rel', column1='deposit', column2='user',
        help='Users that can read to this account')
    state = fields.Selection(selection=[('open', 'Open'),
                                        ('close', 'Closed')],
                             default='open')
    
    @api.onchange('move_ids')
    def _get_amount(self):
        self.amount = 0
        for move in self.move_ids:
            self.amount += move.amount
    
    @api.model
    def _get_balance_day(self, deposit, day):
        move_model = self.env['bank.deposit.move']
        moves = move_model.search([('deposit_id', '=', deposit.id),
                                   ('date', '=', day)], order='date desc')
        
        if len(moves) > 0:
            return moves[0].balance
        else:
            return 0
        
    
    @api.multi
    def button_calculate(self):
        self.compute_interests()

    @api.multi
    def compute_interests(self):
        move_model = self.env['bank.deposit.move']
        for deposit in self:
            date = datetime.strptime(deposit.last_calculate, "%Y-%m-%d")
            end_date = datetime.strptime(fields.Date.today(), "%Y-%m-%d")
            interests = 0
            while (date < end_date):
                date += timedelta(days=1)
                day_balance = self._get_balance_day(deposit, date)
                interests += day_balance * ((deposit.rate.rate/100)/365)
            balance = deposit.amount + interests
            vals = {'name': _('[Interests]'),
                    'date': fields.Date.today(),
                    'amount': interests,
                    'deposit_id': deposit.id,
                    'balance': balance,
                    }
            move_model.create(vals)
            deposit.amount = balance
            deposit.last_calculate = fields.Date.today()
    
    @api.model
    def create(self, vals):
        vals['name'] = self.env['ir.sequence'].get('bank.deposit')
        return super(bank_deposit, self).create(vals)
Exemple #30
0
class ResLetter(models.Model):
    """A register class to log all movements regarding letters"""
    _name = 'res.letter'
    _description = "Log of Letter Movements"
    _inherit = 'mail.thread'

    number = fields.Char(help="Auto Generated Number of letter.", default="/")
    name = fields.Text(string='Subject', help="Subject of letter.")
    move = fields.Selection(
        [('in', 'IN'), ('out', 'OUT')],
        help="Incoming or Outgoing Letter.",
        readonly=True,
        default=lambda self: self.env.context.get('move', 'in'))

    state = fields.Selection([
        ('draft', 'Draft'),
        ('sent', 'Sent'),
        ('rec', 'Received'),
        ('rec_bad', 'Received Damage'),
        ('rec_ret', 'Received But Returned'),
        ('cancel', 'Cancelled'),
    ],
                             default='draft',
                             readonly=True,
                             copy=False,
                             track_visibility='onchange',
                             help="""
            * Draft: not confirmed yet.\n
            * Sent: has been sent, can't be modified anymore.\n
            * Received: has arrived.\n
            * Received Damage: has been received with damages.\n
            * Received But Returned: has been received but returned.\n
            * Cancel: has been cancelled, can't be sent anymore.""")

    date = fields.Date(string='Letter Date',
                       help='The letter\'s date.',
                       default=fields.Date.today)
    snd_date = fields.Date(string='Sent Date',
                           help='The date the letter was sent.')
    rec_date = fields.Date(string='Received Date',
                           help='The date the letter was received.')

    def default_recipient(self):
        move_type = self.env.context.get('move', False)
        if move_type == 'in':
            return self.env.user.company_id.partner_id

    def default_sender(self):
        move_type = self.env.context.get('move', False)
        if move_type == 'out':
            return self.env.user.company_id.partner_id

    recipient_partner_id = fields.Many2one(
        'res.partner',
        string='Recipient',
        track_visibility='onchange',
        # required=True, TODO: make it required in 9.0
        default=default_recipient)
    sender_partner_id = fields.Many2one(
        'res.partner',
        string='Sender',
        track_visibility='onchange',
        # required=True, TODO: make it required in 9.0
        default=default_sender)
    note = fields.Text(string='Delivery Notes',
                       help='Indications for the delivery officer.')

    channel_id = fields.Many2one('letter.channel',
                                 string="Channel",
                                 help='Sent / Receive Source')

    category_ids = fields.Many2many('letter.category',
                                    string="Tags",
                                    help="Classification of Document.")

    folder_id = fields.Many2one('letter.folder',
                                string='Folder',
                                help='Folder which contains letter.')

    type_id = fields.Many2one('letter.type',
                              string="Type",
                              help="Type of Letter, Depending upon size.")

    weight = fields.Float(help='Weight (in KG)')
    size = fields.Char(help='Size of the package.')

    track_ref = fields.Char(string='Tracking Reference',
                            help="Reference Number used for Tracking.")
    orig_ref = fields.Char(string='Original Reference',
                           help="Reference Number at Origin.")
    expeditor_ref = fields.Char(string='Expeditor Reference',
                                help="Reference Number used by Expeditor.")

    parent_id = fields.Many2one('res.letter',
                                string='Parent',
                                groups='lettermgmt.group_letter_thread')
    child_line = fields.One2many('res.letter',
                                 'parent_id',
                                 string='Letter Lines',
                                 groups='lettermgmt.group_letter_thread')

    reassignment_ids = fields.One2many(
        'letter.reassignment',
        'letter_id',
        string='Reassignment lines',
        help='Reassignment users and comments',
        groups='lettermgmt.group_letter_reasignment')

    # This field seems to be unused. TODO: Remove it?
    extern_partner_ids = fields.Many2many('res.partner', string='Recipients')

    @api.model
    def create(self, vals):
        if ('number' not in vals) or (vals.get('number') in ('/', False)):
            sequence = self.env['ir.sequence']
            move_type = vals.get(
                'move',
                self.env.context.get('default_move',
                                     self.env.context.get('move', 'in')))
            vals['number'] = sequence.get('%s.letter' % move_type)
        return super(ResLetter, self).create(vals)

    @api.one
    def action_cancel(self):
        """ Put the state of the letter into Cancelled """
        self.write({'state': 'cancel'})
        return True

    @api.one
    def action_cancel_draft(self):
        """ Go from cancelled state to draf state """
        self.write({'state': 'draft'})
        return True

    @api.one
    def action_send(self):
        """ Put the state of the letter into sent """
        self.write({
            'state': 'sent',
            'snd_date': self.snd_date or fields.Date.today()
        })
        return True

    @api.one
    def action_received(self):
        """ Put the state of the letter into Received """
        self.write({
            'state': 'rec',
            'rec_date': self.rec_date or fields.Date.today()
        })
        return True

    @api.one
    def action_rec_ret(self):
        """ Put the state of the letter into Received but Returned """
        self.write({
            'state': 'rec_ret',
            'rec_date': self.rec_date or fields.Date.today()
        })
        return True

    @api.one
    def action_rec_bad(self):
        """ Put the state of the letter into Received but Damaged """
        self.write({
            'state': 'rec_bad',
            'rec_date': self.rec_date or fields.Date.today()
        })
        return True