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)
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
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, })
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" )
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
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
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
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(), }
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()))
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', })
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'
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
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'}
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'}
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> • <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
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', }
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)
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()
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)
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