class AccountPayment(models.Model): _inherit = 'account.payment' # _name = 'account.check' # _description = 'Account Check' # _order = "id desc" # _inherit = ['mail.thread'] # communication = fields.Char( # # because onchange function is not called on onchange and we want # # to clean check number name # copy=False, # ) # TODO tal vez renombrar a check_ids check_ids = fields.Many2many( 'account.check', # 'account.move.line', # 'check_deposit_id', string='Checks', copy=False, readonly=True, states={'draft': [('readonly', '=', False)]} ) # only for v8 comatibility where more than one check could be received # or issued check_ids_copy = fields.Many2many( related='check_ids', readonly=True, ) readonly_currency_id = fields.Many2one( related='currency_id', readonly=True, ) readonly_amount = fields.Monetary( # string='Payment Amount', # required=True related='amount', readonly=True, ) # we add this field for better usability on issue checks and received # checks. We keep m2m field for backward compatibility where we allow to # use more than one check per payment check_id = fields.Many2one( 'account.check', compute='_compute_check', string='Check', # string='Payment Amount', # required=True ) @api.multi @api.depends('check_ids') def _compute_check(self): for rec in self: # we only show checks for issue checks or received thid checks # if len of checks is 1 if rec.payment_method_code in ( 'received_third_check', 'issue_check',) and len(rec.check_ids) == 1: rec.check_id = rec.check_ids[0].id # check fields, just to make it easy to load checks without need to create # them by a m2o record check_name = fields.Char( 'Check Name', # required=True, readonly=True, copy=False, states={'draft': [('readonly', False)]}, ) check_number = fields.Integer( 'Check Number', # required=True, readonly=True, states={'draft': [('readonly', False)]}, copy=False ) check_issue_date = fields.Date( 'Check Issue Date', # required=True, readonly=True, copy=False, states={'draft': [('readonly', False)]}, default=fields.Date.context_today, ) check_payment_date = fields.Date( 'Check Payment Date', readonly=True, help="Only if this check is post dated", states={'draft': [('readonly', False)]} ) checkbook_id = fields.Many2one( 'account.checkbook', 'Checkbook', readonly=True, states={'draft': [('readonly', False)]}, # TODO hacer con un onchange # default=_get_checkbook, ) check_subtype = fields.Selection( related='checkbook_id.issue_check_subtype', ) check_bank_id = fields.Many2one( 'res.bank', 'Check Bank', readonly=True, copy=False, states={'draft': [('readonly', False)]} ) check_owner_vat = fields.Char( # TODO rename to Owner VAT 'Check Owner Vat', readonly=True, copy=False, states={'draft': [('readonly', False)]} ) check_owner_name = fields.Char( 'Check Owner Name', readonly=True, copy=False, states={'draft': [('readonly', False)]} ) check_type = fields.Char( compute='_compute_check_type', # this fields is to help with code and view ) @api.multi @api.depends('payment_method_code') def _compute_check_type(self): for rec in self: if rec.payment_method_code == 'issue_check': rec.check_type = 'issue_check' elif rec.payment_method_code in [ 'received_third_check', 'delivered_third_check']: rec.check_type = 'third_check' # on change methods # @api.constrains('check_ids') @api.onchange('check_ids', 'payment_method_code') def onchange_checks(self): # we only overwrite if payment method is delivered if self.payment_method_code == 'delivered_third_check': self.amount = sum(self.check_ids.mapped('amount')) # TODo activar @api.one @api.onchange('check_number', 'checkbook_id') def change_check_number(self): # TODO make default padding a parameter if self.payment_method_code in ['received_third_check']: if not self.check_number: check_name = False else: # TODO make optional padding = 8 if len(str(self.check_number)) > padding: padding = len(str(self.check_number)) # communication = _('Check nbr %s') % ( check_name = ('%%0%sd' % padding % self.check_number) # communication = ( # '%%0%sd' % padding % self.check_number) self.check_name = check_name @api.onchange('check_issue_date', 'check_payment_date') def onchange_date(self): if ( self.check_issue_date and self.check_payment_date and self.check_issue_date > self.check_payment_date): self.check_payment_date = False raise UserError( _('Check Payment Date must be greater than Issue Date')) @api.one @api.onchange('partner_id') def onchange_partner_check(self): commercial_partner = self.partner_id.commercial_partner_id self.check_bank_id = ( commercial_partner.bank_ids and commercial_partner.bank_ids[0].bank_id.id or False) self.check_owner_name = commercial_partner.name # TODO use document number instead of vat? self.check_owner_vat = commercial_partner.vat @api.onchange('payment_method_code') def _onchange_payment_method_code(self): if self.payment_method_code == 'issue_check': checkbook = self.env['account.checkbook'].search([ ('state', '=', 'active'), ('journal_id', '=', self.journal_id.id)], limit=1) self.checkbook_id = checkbook @api.onchange('checkbook_id') def onchange_checkbook(self): if self.checkbook_id: self.check_number = self.checkbook_id.next_number # post methods @api.model def create(self, vals): issue_checks = self.env.ref( 'account_check.account_payment_method_issue_check') if vals['payment_method_id'] == issue_checks.id and vals.get( 'checkbook_id'): checkbook = self.env['account.checkbook'].browse( vals['checkbook_id']) vals.update({ # beacause number was readonly we write it here 'check_number': checkbook.next_number, 'check_name': checkbook.sequence_id.next_by_id(), }) return super(AccountPayment, self.sudo()).create(vals) @api.multi def cancel(self): res = super(AccountPayment, self).cancel() for rec in self: rec.do_checks_operations(cancel=True) # if rec.check_id: # # rec.check_id._add_operation('cancel') # rec.check_id._del_operation() # rec.check_id.unlink() # elif rec.check_ids: # rec.check_ids._del_operation() return res @api.multi def create_check(self, check_type, operation, bank): self.ensure_one() check_vals = { 'bank_id': bank.id, 'owner_name': self.check_owner_name, 'owner_vat': self.check_owner_vat, 'number': self.check_number, 'name': self.check_name, 'checkbook_id': self.checkbook_id.id, 'issue_date': self.check_issue_date, 'type': self.check_type, 'journal_id': self.journal_id.id, 'amount': self.amount, 'payment_date': self.check_payment_date, # TODO arreglar que monto va de amount y cual de amount currency # 'amount_currency': self.amount, 'currency_id': self.currency_id.id, } check = self.env['account.check'].create(check_vals) self.check_ids = [(4, check.id, False)] check._add_operation(operation, self, self.partner_id) return check @api.multi def get_third_check_account(self): """ For third checks, if we use a journal only for third checks, we use accounts on journal, if not we use company account """ self.ensure_one() if self.payment_type in ('outbound', 'transfer'): account = self.journal_id.default_debit_account_id methods_field = 'outbound_payment_method_ids' else: account = self.journal_id.default_credit_account_id methods_field = 'inbound_payment_method_ids' if len(self.journal_id[methods_field]) > 1 or not account: account = self.company_id._get_check_account('holding') return account @api.multi def do_checks_operations(self, vals=None, cancel=False): """ Check attached .ods file on this module to understand checks workflows This method is called from: * cancellation of payment to execute delete the right operation and unlink check if needed * from _get_liquidity_move_line_vals to add check operation and, if needded, change payment vals and/or create check and """ self.ensure_one() rec = self if not rec.check_type: # continue return vals if ( rec.payment_method_code == 'received_third_check' and rec.payment_type == 'inbound' and rec.partner_type == 'customer'): operation = 'holding' if cancel: _logger.info('Cancel Receive Check') rec.check_ids._del_operation(operation) rec.check_ids.unlink() return None _logger.info('Receive Check') self.create_check('third_check', operation, self.check_bank_id) vals['date_maturity'] = self.check_payment_date vals['account_id'] = self.get_third_check_account().id elif ( rec.payment_method_code == 'delivered_third_check' and rec.payment_type == 'transfer' and rec.destination_journal_id.type == 'cash'): operation = 'selled' if cancel: _logger.info('Cancel Sell Check') rec.check_ids._del_operation(operation) return None _logger.info('Sell Check') rec.check_ids._add_operation( operation, rec, False) vals['account_id'] = self.get_third_check_account().id elif ( rec.payment_method_code == 'delivered_third_check' and rec.payment_type == 'transfer' and rec.destination_journal_id.type == 'bank'): operation = 'deposited' if cancel: _logger.info('Cancel Deposit Check') rec.check_ids._del_operation(operation) return None _logger.info('Deposit Check') rec.check_ids._add_operation( operation, rec, False) vals['account_id'] = self.get_third_check_account().id elif ( rec.payment_method_code == 'delivered_third_check' and rec.payment_type == 'outbound' and rec.partner_type == 'supplier'): operation = 'delivered' if cancel: _logger.info('Cancel Deliver Check') rec.check_ids._del_operation(operation) return None _logger.info('Deliver Check') rec.check_ids._add_operation( operation, rec, rec.partner_id) vals['account_id'] = self.get_third_check_account().id elif ( rec.payment_method_code == 'issue_check' and rec.payment_type == 'outbound' and rec.partner_type == 'supplier'): operation = 'handed' if cancel: _logger.info('Cancel Hand Check') rec.check_ids._del_operation(operation) rec.check_ids.unlink() return None _logger.info('Hand Check') self.create_check('issue_check', operation, self.check_bank_id) vals['date_maturity'] = self.check_payment_date # if check is deferred, change account if self.check_subtype == 'deferred': vals['account_id'] = self.company_id._get_check_account( 'deferred').id elif ( rec.payment_method_code == 'issue_check' and rec.payment_type == 'transfer' and rec.destination_journal_id.type == 'cash'): operation = 'withdrawed' if cancel: _logger.info('Cancel Withdrawal Check') rec.check_ids._del_operation(operation) rec.check_ids.unlink() return None _logger.info('Hand Check') self.create_check('issue_check', operation, self.check_bank_id) vals['date_maturity'] = self.check_payment_date # if check is deferred, change account # si retiramos por caja directamente lo sacamos de banco # if self.check_subtype == 'deferred': # vals['account_id'] = self.company_id._get_check_account( # 'deferred').id else: raise UserError(_( 'This operatios is not implemented for checks:\n' '* Payment type: %s\n' '* Partner type: %s\n' '* Payment method: %s\n' '* Destination journal: %s\n' % ( rec.payment_type, rec.partner_type, rec.payment_method_code, rec.destination_journal_id.type))) return vals # @api.multi # def post(self): # self.do_checks_operations() # return super(AccountPayment, self).post() def _get_liquidity_move_line_vals(self, amount): vals = super(AccountPayment, self)._get_liquidity_move_line_vals( amount) vals = self.do_checks_operations(vals=vals) # if self.check_type: # vals['date_maturity'] = self.check_payment_date # if self.check_subtype == 'deferred': # deferred_account = self.company_id.deferred_check_account_id # if not deferred_account: # raise UserError(_( # 'No checks deferred account defined for company %s' # ) % self.company_id.name) # vals['account_id'] = deferred_account.id # # vals['check_bank_id'] = self.check_bank_id.id # # vals['check_owner_name'] = self.check_owner_name # # vals['check_owner_vat'] = self.check_owner_vat # # vals['check_number'] = self.check_number # # vals['checkbook_id'] = self.checkbook_id.id # # vals['check_issue_date'] = self.check_issue_date # # if self.payment_method_code == 'issue_check': # # vals['check_type'] = 'issue_check' # # else: # # vals['check_type'] = 'third_check' return vals
class SparkProject(models.Model): _name = 'sparkit.sparkproject' _inherit = 'mail.thread' name = fields.Char(compute='_get_project_name', track_visibility='always') #---- Basic Project Information ----# community_id = fields.Many2one('sparkit.community', string="Community", required=True, domain=[('is_partnered', '=', True)], ondelete='cascade', track_visibility='onchange') facilitator_id = fields.Many2one('res.users', string="Facilitator", related="community_id.facilitator_id") community_number = fields.Char(related='community_id.community_number', track_visibility='onchange') community_name = fields.Char(related='community_id.name', track_visibility='onchange') category_id = fields.Many2one('sparkit.projectcategory', string="Category", required=True, track_visibility='onchange') subcategory_id = fields.Many2one('sparkit.projectsubcategory', string="Sub-Category", track_visibility='onchange') grant_agreement_date = fields.Date(string="Grant Agreement Date", track_visibility='onchange') grant_amount = fields.Float(string="Grant Amount - USD", track_visibility='onchange', compute='_get_usd_grant_amount', readonly=True) grant_amount_local = fields.Float(string="Grant Amount - Local Currency", track_visibility='onchange') country_id = fields.Many2one(related='community_id.country_id', readonly=True, track_visibility='onchange') currency_id = fields.Many2one(related='country_id.currency_id', readonly=True, store=True, track_visibility='onchange') exchange_rate = fields.Float(string="Exchange Rate", compute='_get_exchange_rate', store=True, track_visibility='onchange') #-- Donor Info --# donor_funded = fields.Boolean(string="Donor Funded") donor_ids = fields.One2many('sparkit.projectdonation', 'project_id', string="Project Donors") #-- Budgeted Contribution Summary --# spark_contribution = fields.Float(string="Spark", readonly=True, compute='_spark_contribution', store=True, track_visibility='onchange') spark_contribution_percent = fields.Float(string="Spark Contribution %", readonly=True, compute='_spark_contribution_percent', store=True, track_visibility='onchange') inkind_community_contribution = fields.Float(string="In-Kind Community Contribution", store=True, compute='_inkind_community_contribution') cash_community_contribution = fields.Float(string="Cash Community Contribution", store=True, compute='_cash_community_contribution') community_contribution = fields.Float(string="Community", readonly=True, compute='_community_contribution', store=True, track_visibility='onchange') community_contribution_percent = fields.Float(string="Community Contribution %", readonly=True, compute='_community_contribution_percent', store=True, track_visibility='onchange') fvs_contribution = fields.Float(string="FVS-AMADE", readonly=True, compute='_fvs_contribution', store=True, track_visibility='onchange') fvs_contribution_percent = fields.Float(string="FVS-AMADE Contribution %", readonly=True, compute='_fvs_contribution_percent', store=True, track_visibility='onchange') other_contribution = fields.Float(string="Other", readonly=True, compute='_other_contribution', store=True, track_visibility='onchange') other_contribution_percent = fields.Float(string="Other Contribution %", readonly=True, compute='_other_contribution_percent', store=True, track_visibility='onchange') total = fields.Float(string="Total Budget", readonly=True, compute='_total', store=True, help="Includes both Spark, community, FVS, and other contributions.", track_visibility='onchange') grant_surplus = fields.Float(string="Grant Surplus", readonly=True, compute='_grant_surplus', store=True, track_visibility='onchange', help="This field is calculated from the total budgeted items allocated to Spark and the overall grant size.") #---- Budget Information ----# budget_line_item_ids = fields.One2many('sparkit.projectbudgetitem', 'project_id', string="Budget Line Items", track_visibility='onchange') #--- Transactions ---# transaction_ids = fields.One2many('sparkit.transaction', 'project_id', string="Transactions", track_visibility='onchange') total_expenditure = fields.Float(string="Total Expenditure", readonly=True, store=True, compute='_get_total_expenditure', track_visibility='onchange') bank_balance = fields.Float(string="Bank Balance", track_visibility='onchange') outstanding_receipts = fields.Float(string="Outstanding Receipts", readonly=True, store=True, compute='_get_outstanding_receipts', track_visibility='onchange') outstanding_receipts_dollars = fields.Float(string="Outstanding Receipts - $", store=True, compute='_get_oustanding_receipt_dollars') #-- Disbursals --# disbursal_ids = fields.One2many('sparkit.disbursal', 'project_id', string="Disbursals", track_visibility='onchange') number_disbursals = fields.Integer(readonly=True, store=True, compute='_get_number_disbursals', string="Number of Disbursals", track_visibility='onchange') total_disbursed = fields.Float(readonly=True, store=True, compute='_get_total_disbursed', string="Total Disbursed", track_visibility='onchange') left_to_disburse = fields.Float(string="Left to Disburse", readonly=True, store=True, compute='_get_left_to_disburse', track_visibility='onchange') last_disbursal_date = fields.Date(string="Last Disbursement", compute='get_last_disbursement', track_visibility='onchange') #-- Disbursal Requests--# disbursal_request_ids = fields.One2many('sparkit.disbursalrequest', 'project_id', string="Disbursal Requests", track_visibility='onchange') number_requests = fields.Integer(string="Number of Disbursal Requests", readonly=True, store=True, compute='_get_number_disbursal_requests', track_visibility='onchange') #-- Project Support Initiatives --# project_support_initiative_ids = fields.One2many('sparkit.projectsupportinitiative', 'project_id', string="Project Support Initiatives", track_visibility='onchange') #This function counts the number of disbursal requests made by the community @api.multi @api.depends('disbursal_request_ids') def _get_number_disbursal_requests(self): for r in self: r.number_requests = len(r.disbursal_request_ids) # Calculates exchange rate when budget is formed @api.multi @api.depends('currency_id') def _get_exchange_rate(self): for r in self: if r.currency_id: r.exchange_rate = r.currency_id.rate @api.multi @api.depends('disbursal_ids') def get_last_disbursement(self): for r in self: if r.disbursal_ids: r.last_disbursal_date = max(line.date for line in r.disbursal_ids) #Uses total expenditure to date (from the transactions object) and #total disbursed (from the disbursals object) to calculate the #amount in outstanding receipts @api.depends('total_expenditure', 'total_disbursed', 'bank_balance') def _get_outstanding_receipts(self): for r in self: r.outstanding_receipts = r.total_disbursed - r.bank_balance - r.total_expenditure @api.depends('outstanding_receipts', 'grant_amount') def _get_oustanding_receipt_dollars(self): for r in self: if r.outstanding_receipts and r.exchange_rate: r.outstanding_receipts_dollars = r.outstanding_receipts / r.exchange_rate #Counts the total amount spent by communities if the budget source is equal to Spark @api.multi @api.depends('transaction_ids', 'budget_line_item_ids') def _get_total_expenditure(self): for r in self: r.total_expenditure = sum(s.actual for s in r.budget_line_item_ids if s.source == "spark") #Calculates the remaining grant balance (total grant - total disbursed) @api.depends('total_disbursed', 'grant_amount_local') def _get_left_to_disburse(self): for r in self: r.left_to_disburse = r.grant_amount_local - r.total_disbursed #Counts the number of disbursals made to the community @api.multi @api.depends('disbursal_ids') def _get_number_disbursals(self): for r in self: r.number_disbursals = len(r.disbursal_ids) #Sums the amount disbursed to the community (in the disbursals object) @api.multi @api.depends('disbursal_ids') def _get_total_disbursed(self): for r in self: r.total_disbursed = sum(s.amount for s in r.disbursal_ids) #Concatenates the community number and name to come up with a project name @api.multi @api.depends('community_id', 'category_id') def _get_project_name(self): for r in self: if r.community_id and r.category_id: r.name = r.country_id.name + ': ' + r.community_number + ': ' + r.community_name + ': ' + r.category_id.name #Calculates the grant surplus (total grant - total budgeted) - relevant #for Standardized Grant Communities @api.depends('total', 'grant_amount_local') def _grant_surplus(self): for r in self: r.grant_surplus = r.grant_amount_local - r.spark_contribution #Counts the total budgeted @api.multi @api.depends('budget_line_item_ids') def _total(self): for r in self: r.total = sum(s.budgeted for s in r.budget_line_item_ids) #Counts the total amount budgeted for Spark to provide @api.multi @api.depends('budget_line_item_ids') def _spark_contribution(self): for r in self: r.spark_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "spark") @api.multi @api.depends('budget_line_item_ids') def _inkind_community_contribution(self): for r in self: r.inkind_community_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "community_in_kind") @api.multi @api.depends('budget_line_item_ids') def _cash_community_contribution(self): for r in self: r.cash_community_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "community_cash") #Counts the total amount budgeted for the Community to provide, including both inkind and cash @api.multi @api.depends('inkind_community_contribution', 'cash_community_contribution') def _community_contribution(self): for r in self: r.community_contribution = r.inkind_community_contribution + r.cash_community_contribution #Counts the total amount budgeted for another organization/government to provide @api.multi @api.depends('budget_line_item_ids') def _other_contribution(self): for r in self: r.other_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "other") #Counts the total amount budgeted for FVS-AMADE to provide @api.multi @api.depends('budget_line_item_ids') def _fvs_contribution(self): for r in self: r.fvs_contribution = sum(s.budgeted for s in r.budget_line_item_ids if s.source == "FVS-AMADE") #Counts the percentage of the total project budget contributed by Spark @api.depends('spark_contribution', 'total') def _spark_contribution_percent(self): for r in self: if r.total>0: r.spark_contribution_percent = (r.spark_contribution / r.total) * 100 #Counts the percentage of the total project budget contributed by the community @api.depends('community_contribution', 'total') def _community_contribution_percent(self): for r in self: if r.total >0: r.community_contribution_percent = (r.community_contribution / r.total) * 100 #Counts the percentage of the total project budget contributed by FVS-AMADE @api.depends('fvs_contribution', 'total') def _fvs_contribution_percent(self): for r in self: if r.total >0: r.fvs_contribution_percent = (r.fvs_contribution / r.total) * 100 #Counts the percentage of the total project budget contributed by another partner @api.depends('other_contribution', 'total') def _other_contribution_percent(self): for r in self: if r.total >0: r.other_contribution_percent = (r.other_contribution / r.total) * 100 #Calculates the total grant amount in local currency using Spark's exchange rate @api.depends('grant_amount_local', 'exchange_rate') def _get_usd_grant_amount(self): for r in self: if r.exchange_rate>0: r.grant_amount = r.grant_amount_local / r.exchange_rate
class event_event(models.Model): """Event""" _name = 'event.event' _description = 'Event' _inherit = ['mail.thread', 'ir.needaction_mixin'] _order = 'date_begin' name = fields.Char(string='Event Name', translate=True, required=True, readonly=False, states={'done': [('readonly', True)]}) active = fields.Boolean(default=True, track_visibility="onchange") user_id = fields.Many2one('res.users', string='Responsible', default=lambda self: self.env.user, readonly=False, states={'done': [('readonly', True)]}) company_id = fields.Many2one('res.company', string='Company', change_default=True, default=lambda self: self.env['res.company']. _company_default_get('event.event'), required=False, readonly=False, states={'done': [('readonly', True)]}) organizer_id = fields.Many2one( 'res.partner', string='Organizer', default=lambda self: self.env.user.company_id.partner_id) event_type_id = fields.Many2one('event.type', string='Category', readonly=False, states={'done': [('readonly', True)]}, oldname='type') color = fields.Integer('Kanban Color Index') event_mail_ids = fields.One2many( 'event.mail', 'event_id', string='Mail Schedule', default=lambda self: self._default_event_mail_ids(), copy=True) @api.model def _default_event_mail_ids(self): return [(0, 0, { 'interval_unit': 'now', 'interval_type': 'after_sub', 'template_id': self.env.ref('event.event_subscription') })] # Seats and computation seats_max = fields.Integer( string='Maximum Attendees Number', oldname='register_max', readonly=True, states={ 'draft': [('readonly', False)], 'confirm': [('readonly', False)] }, help= "For each event you can define a maximum registration of seats(number of attendees), above this numbers the registrations are not accepted." ) seats_availability = fields.Selection([('limited', 'Limited'), ('unlimited', 'Unlimited')], 'Maximum Attendees', required=True, default='unlimited') seats_min = fields.Integer( string='Minimum Attendees', oldname='register_min', help= "For each event you can define a minimum reserved seats (number of attendees), if it does not reach the mentioned registrations the event can not be confirmed (keep 0 to ignore this rule)" ) seats_reserved = fields.Integer(oldname='register_current', string='Reserved Seats', store=True, readonly=True, compute='_compute_seats') seats_available = fields.Integer(oldname='register_avail', string='Maximum Attendees', store=True, readonly=True, compute='_compute_seats') seats_unconfirmed = fields.Integer(oldname='register_prospect', string='Unconfirmed Seat Reservations', store=True, readonly=True, compute='_compute_seats') seats_used = fields.Integer(oldname='register_attended', string='Number of Participants', store=True, readonly=True, compute='_compute_seats') seats_expected = fields.Integer(string='Number of Expected Attendees', readonly=True, compute='_compute_seats') @api.multi @api.depends('seats_max', 'registration_ids.state') def _compute_seats(self): """ Determine reserved, available, reserved but unconfirmed and used seats. """ # initialize fields to 0 for event in self: event.seats_unconfirmed = event.seats_reserved = event.seats_used = event.seats_available = 0 # aggregate registrations by event and by state if self.ids: state_field = { 'draft': 'seats_unconfirmed', 'open': 'seats_reserved', 'done': 'seats_used', } query = """ SELECT event_id, state, count(event_id) FROM event_registration WHERE event_id IN %s AND state IN ('draft', 'open', 'done') GROUP BY event_id, state """ self._cr.execute(query, (tuple(self.ids), )) for event_id, state, num in self._cr.fetchall(): event = self.browse(event_id) event[state_field[state]] += num # compute seats_available for event in self: if event.seats_max > 0: event.seats_available = event.seats_max - ( event.seats_reserved + event.seats_used) event.seats_expected = event.seats_unconfirmed + event.seats_reserved + event.seats_used # Registration fields registration_ids = fields.One2many('event.registration', 'event_id', string='Attendees', readonly=False, states={'done': [('readonly', True)]}) # Date fields date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz) date_begin = fields.Datetime(string='Start Date', required=True, track_visibility='onchange', states={'done': [('readonly', True)]}) date_end = fields.Datetime(string='End Date', required=True, track_visibility='onchange', states={'done': [('readonly', True)]}) date_begin_located = fields.Datetime(string='Start Date Located', compute='_compute_date_begin_tz') date_end_located = fields.Datetime(string='End Date Located', compute='_compute_date_end_tz') @api.model def _tz_get(self): return [(x, x) for x in pytz.all_timezones] @api.one @api.depends('date_tz', 'date_begin') def _compute_date_begin_tz(self): if self.date_begin: self_in_tz = self.with_context(tz=(self.date_tz or 'UTC')) date_begin = fields.Datetime.from_string(self.date_begin) self.date_begin_located = fields.Datetime.to_string( fields.Datetime.context_timestamp(self_in_tz, date_begin)) else: self.date_begin_located = False @api.one @api.depends('date_tz', 'date_end') def _compute_date_end_tz(self): if self.date_end: self_in_tz = self.with_context(tz=(self.date_tz or 'UTC')) date_end = fields.Datetime.from_string(self.date_end) self.date_end_located = fields.Datetime.to_string( fields.Datetime.context_timestamp(self_in_tz, date_end)) else: self.date_end_located = False state = fields.Selection( [('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), ('confirm', 'Confirmed'), ('done', 'Done')], string='Status', default='draft', readonly=True, required=True, copy=False, help= "If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'." ) auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm') @api.one def _compute_auto_confirm(self): self.auto_confirm = self.env['ir.values'].get_default( 'event.config.settings', 'auto_confirmation') reply_to = fields.Char( 'Reply-To Email', readonly=False, states={'done': [('readonly', True)]}, help= "The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one." ) address_id = fields.Many2one( 'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id, readonly=False, states={'done': [('readonly', True)]}) country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True) description = fields.Html(string='Description', oldname='note', translate=True, readonly=False, states={'done': [('readonly', True)]}) # badge fields badge_front = fields.Html(string='Badge Front') badge_back = fields.Html(string='Badge Back') badge_innerleft = fields.Html(string='Badge Inner Left') badge_innerright = fields.Html(string='Badge Inner Right') event_logo = fields.Html(string='Event Logo') @api.multi @api.depends('name', 'date_begin', 'date_end') def name_get(self): result = [] for event in self: date_begin = fields.Datetime.from_string(event.date_begin) date_end = fields.Datetime.from_string(event.date_end) dates = [ fields.Date.to_string( fields.Datetime.context_timestamp(event, dt)) for dt in [date_begin, date_end] if dt ] dates = sorted(set(dates)) result.append( (event.id, '%s (%s)' % (event.name, ' - '.join(dates)))) return result @api.one @api.constrains('seats_max', 'seats_available') def _check_seats_limit(self): if self.seats_availability == 'limited' and self.seats_max and self.seats_available < 0: raise ValidationError(_('No more available seats.')) @api.one @api.constrains('date_begin', 'date_end') def _check_closing_date(self): if self.date_end < self.date_begin: raise ValidationError( _('Closing Date cannot be set before Beginning Date.')) @api.model def create(self, vals): res = super(event_event, self).create(vals) if res.organizer_id: res.message_subscribe([res.organizer_id.id]) if res.auto_confirm: res.button_confirm() return res @api.multi def write(self, vals): res = super(event_event, self).write(vals) if vals.get('organizer_id'): self.message_subscribe([vals['organizer_id']]) return res @api.one def button_draft(self): self.state = 'draft' @api.one def button_cancel(self): for event_reg in self.registration_ids: if event_reg.state == 'done': raise UserError( _("You have already set a registration for this event as 'Attended'. Please reset it to draft if you want to cancel this event." )) self.registration_ids.write({'state': 'cancel'}) self.state = 'cancel' @api.one def button_done(self): self.state = 'done' @api.one def button_confirm(self): self.state = 'confirm' @api.onchange('event_type_id') def _onchange_type(self): if self.event_type_id: self.seats_min = self.event_type_id.default_registration_min self.seats_max = self.event_type_id.default_registration_max self.reply_to = self.event_type_id.default_reply_to @api.multi def action_event_registration_report(self): res = self.env['ir.actions.act_window'].for_xml_id( 'event', 'action_report_event_registration') res['context'] = { "search_default_event_id": self.id, "group_by": ['create_date:day'], } return res @api.one def mail_attendees(self, template_id, force_send=False, filter_func=lambda self: True): for attendee in self.registration_ids.filtered(filter_func): self.env['mail.template'].browse(template_id).send_mail( attendee.id, force_send=force_send)
class AssetRegisterReport(models.TransientModel): _name = 'asset.register.report' _inherit = 'report.account.common' filter = fields.Selection( readonly=True, default='filter_date', ) asset_status_ids = fields.Many2many( 'account.asset.status', string='Asset Status', ) asset_filter = fields.Text( string='Filter', help="More filter. You can use complex search with comma and between.", ) asset_ids = fields.Many2many( 'account.asset', string='Asset Code', ) count_asset = fields.Integer( compute='_compute_count_asset', string='Asset Count', ) asset_profile_ids = fields.Many2many( 'account.asset.profile', string='Asset Profile', required=False, ) responsible_person_ids = fields.Many2many( 'res.users', string='Responsible Person', ) building_ids = fields.Many2many( 'res.building', string='Building', ) floor_ids = fields.Many2many( 'res.floor', string='Floor', ) room_ids = fields.Many2many( 'res.room', string='Room', ) org_ids = fields.Many2many( 'res.org', string='Org', ) asset_state = fields.Many2many( 'xlsx.report.status', string='Asset State', domain=[('location', '=', 'asset.register.view')], default=lambda self: self.env['xlsx.report.status'].search( [('location', '=', 'asset.register.view'), ('status', 'in', ['draft', 'open', 'close', 'removed'])]), ) account_ids = fields.Many2many( 'account.account', string='Account Code', ) costcenter_ids = fields.Many2many( 'res.costcenter', string='Cost Center', ) division_ids = fields.Many2many( 'res.division', string='Division', ) sector_ids = fields.Many2many( 'res.sector', string='Sector', ) subsector_ids = fields.Many2many( 'res.subsector', string='Subsector', ) current_year = fields.Many2one( 'account.fiscalyear', string='Current Year', default=lambda self: self._get_fiscalyear(), ) # Note: report setting accum_depre_account_type = fields.Many2one( 'account.account.type', string='Account Type for Accum.Depre.', required=True, help="Define account type for accumulated depreciation account, " "to be used in report query SQL.") depre_account_type = fields.Many2one( 'account.account.type', string='Account Type for Depre.', required=True, help="Define account type for depreciation account, " "to be used in report query SQL.") # More fileter budget_filter = fields.Text( string='Filter', help="More filter. You can use complex search with comma and between.", ) budget = fields.Many2many( 'chartfield.view', 'asset_register_chartfield_rel', 'wizard_id', 'chartfield_id', string='Source Budget', domain=[('model', '!=', 'res.personnel.costcenter')], ) count_budget = fields.Integer( compute='_compute_count_budget', string='Budget Count', ) owner_budget_filter = fields.Text( string='Filter', help="More filter. You can use complex search with comma and between.", ) owner_budget = fields.Many2many( 'chartfield.view', 'asset_register_owner_chartfield_rel', 'wizard_id', 'chartfield_id', string='Owner Budget', domain=[('model', '!=', 'res.personnel.costcenter')], ) count_owner_budget = fields.Integer( compute='_compute_count_budget', string='Budget Count', ) asset_active = fields.Selection( [('active', 'Active'), ('inactive', 'Inactive')], string='Asset Active', #default='active', ) results = fields.Many2many( 'asset.register.view', string='Results', compute='_compute_results', help='Use compute fields, so there is nothing store in database', ) @api.multi @api.depends('asset_ids') def _compute_count_asset(self): for rec in self: rec.count_asset = len(rec.asset_ids) @api.multi @api.depends('budget', 'owner_budget') def _compute_count_budget(self): for rec in self: rec.count_budget = len(rec.budget) rec.count_owner_budget = len(rec.owner_budget) # @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.model def _domain_to_where_str(self, domain): """ Helper Function for better performance """ where_dom = [ " %s %s %s " % (x[0], x[1], isinstance(x[2], basestring) and "'%s'" % x[2] or x[2]) for x in domain ] where_str = 'and'.join(where_dom) return where_str @api.multi def _compute_results(self): self.ensure_one() dom = [] # Prepare DOM to filter assets if self.asset_filter: self._onchange_asset_filter() if self.asset_ids: dom += [('id', 'in', tuple(self.asset_ids.ids + [0]))] if self.asset_profile_ids: dom += [('profile_id', 'in', tuple(self.asset_profile_ids.ids + [0]))] if self.responsible_person_ids: dom += [('responsible_user_id', 'in', tuple(self.responsible_person_ids.ids + [0]))] if self.org_ids: dom += [('owner_org_id', 'in', tuple(self.org_ids.ids + [0]))] if self.asset_status_ids: dom += [('status', 'in', tuple(self.asset_status_ids.ids + [0]))] if self.account_ids: dom += [('account_asset_id', 'in', tuple(self.account_ids.ids + [0]))] if self.budget: dom_budget = \ ["%s,%s" % ((x.model).encode('utf-8'), x.res_id) for x in self.budget] dom += [('budget', 'in', tuple(dom_budget + ['0']))] if self.owner_budget: dom_owner = \ ["%s,%s" % ((x.model).encode('utf-8'), x.res_id) for x in self.owner_budget] dom += [('owner_budget', 'in', tuple(dom_owner + ['0']))] if self.costcenter_ids: dom += [('owner_costcenter_id', 'in', tuple(self.costcenter_ids.ids + [0]))] if self.division_ids: dom += [('owner_division_id', 'in', tuple(self.division_ids.ids + [0]))] if self.sector_ids: dom += [('owner_sector_id', 'in', tuple(self.sector_ids.ids + [0])) ] if self.subsector_ids: dom += [('owner_subsector_id', 'in', tuple(self.subsector_ids.ids + [0]))] if self.asset_state: res, state_name = [], self.asset_state for state in self.asset_state: state_name = self.env['xlsx.report.status'].search([ ('id', '=', state.id) ]) res += [str(state_name.status)] if len(self.asset_state) == 1: dom += [('state', '=', str(state_name.status))] else: dom += [('state', 'in', tuple(res))] if self.building_ids: dom += [('building_id', 'in', tuple(self.building_ids.ids + [0]))] if self.floor_ids: dom += [('floor_id', 'in', tuple(self.floor_ids.ids + [0]))] if self.room_ids: dom += [('room_id', 'in', tuple(self.room_ids.ids + [0]))] if self.asset_active: if self.asset_active == 'active': dom += [('active', '=', True)] elif self.asset_active == 'inactive': dom += [('active', '=', False)] # date_start <= date_end if self.date_end: dom += [('date_start', '<=', self.date_end)] # Prepare fixed params date_start = False date_end = False if self.filter == 'filter_date': date_start = self.date_start #self.fiscalyear_start_id.date_start date_end = self.date_end if self.filter == 'filter_period': date_start = self.period_start_id.date_start date_end = self.period_end_id.date_stop if not date_start or not date_end: raise ValidationError(_('Please provide from and to dates.')) accum_depre_account_ids = self.env['account.account'].search([ ('user_type', '=', self.accum_depre_account_type.id) ]).ids depre_account_ids = self.env['account.account'].search([ ('user_type', '=', self.depre_account_type.id) ]).ids where_str = self._domain_to_where_str(dom) if where_str: where_str = 'where ' + where_str self._cr.execute( """ select * from ( select a.*, a.id asset_id, aap.account_asset_id, aa.code as account_code, aa.name as account_name, -- purchase_bf_current case when date_part('year', a.date_start+92) != CAST(%s AS int) then a.purchase_value else null end as purchase_before_current, -- purchase_current case when date_part('year', a.date_start+92) = CAST(%s AS int) then a.purchase_value else null end as purchase_current, -- net_book_value (select a.purchase_value - coalesce(sum(credit-debit), 0.0) from account_move_line ml where account_id in %s -- accumulated account and ml.date <= %s -- date end and asset_id = a.id) net_book_value, -- budget_type case when a.section_id is not null then 'Section' when a.project_id is not null then 'Project' when a.invest_asset_id is not null then 'Invest Asset' when a.invest_construction_phase_id is not null then 'Invest Construction Phase' else null end as budget_type, -- budget case when a.section_id is not null then concat('res.section,', a.section_id) when a.project_id is not null then concat('res.project,', a.project_id) when a.invest_asset_id is not null then concat('res.invest.asset,', a.invest_asset_id) when a.invest_construction_phase_id is not null then concat('res.invest.construction.phase,', a.invest_construction_phase_id) else null end as budget, -- owner_org_id case when a.owner_section_id is not null then rs.org_id when a.owner_project_id is not null then rp.org_id when a.owner_invest_asset_id is not null then ria.org_id when a.owner_invest_construction_phase_id is not null then ricp.org_id else null end as owner_org_id, -- owner_budget case when a.owner_section_id is not null then concat('res.section,', a.owner_section_id) when a.owner_project_id is not null then concat('res.project,', a.owner_project_id) when a.owner_invest_asset_id is not null then concat('res.invest.asset,', a.owner_invest_asset_id) when a.owner_invest_construction_phase_id is not null then concat('res.invest.construction.phase,', a.owner_invest_construction_phase_id) else null end as owner_budget, -- owner_costcenter case when a.owner_section_id is not null then rs.costcenter_id when a.owner_project_id is not null then rp.costcenter_id when a.owner_invest_asset_id is not null then ria.costcenter_id when a.owner_invest_construction_phase_id is not null then ricp.costcenter_id else null end as owner_costcenter_id, -- owner_division case when a.owner_section_id is not null then rs.division_id else null end as owner_division_id, -- owner_sector case when a.owner_section_id is not null then rs.sector_id else null end as owner_sector_id, -- owner_subsector case when a.owner_section_id is not null then rs.subsector_id else null end as owner_subsector_id, -- depreciation (select coalesce(sum(debit-credit), 0.0) from account_move_line ml where account_id in %s -- depreciation account and ml.date between %s and %s and asset_id = a.id) depreciation, -- accumulated_cf (select coalesce(sum(credit-debit), 0.0) from account_move_line ml where account_id in %s -- accumulated account and ml.date <= %s -- date end and asset_id = a.id) accumulated_cf, -- accumulated_bf (select coalesce(sum(credit-debit), 0.0) from account_move_line ml where account_id in %s -- accumulatedp account and ml.date < %s -- date start and asset_id = a.id) accumulated_bf from account_asset a left join account_asset_profile aap on a.profile_id = aap.id left join res_section rs on a.owner_section_id = rs.id left join res_project rp on a.owner_project_id = rp.id left join res_invest_asset ria on a.owner_invest_asset_id = ria.id left join res_invest_construction_phase ricp on a.owner_invest_construction_phase_id = ricp.id left join account_account aa on aap.account_asset_id = aa.id ) asset """ + where_str + 'order by asset.account_code, asset.code', (self.fiscalyear_start_id.name, self.fiscalyear_start_id.name, tuple(accum_depre_account_ids), date_end, tuple(depre_account_ids), date_start, date_end, tuple(accum_depre_account_ids), date_end, tuple(accum_depre_account_ids), date_start)) results = self._cr.dictfetchall() ReportLine = self.env['asset.register.view'] self.results = [ReportLine.new(line).id for line in results] return True # @api.multi # def action_get_report(self): # action = self.env.ref( # 'pabi_account_report.action_asset_register_report_form') # return super(AssetRegisterReport, self).action_get_report() @api.onchange('asset_filter') def _onchange_asset_filter(self): self.asset_ids = [] Asset = self.env['account.asset'] dom = [] if self.asset_filter: codes = self.asset_filter.split('\n') codes = [x.strip() for x in codes] codes = ','.join(codes) dom.append(('code', 'ilike', codes)) self.asset_ids = Asset.with_context(active_test=False).search( dom, order='id') @api.onchange('budget_filter') def _onchange_budget_filter(self): self.budget = [] Chartfield = self.env['chartfield.view'] dom = [] if self.budget_filter: codes = self.budget_filter.split('\n') codes = [x.strip() for x in codes] codes = ','.join(codes) dom.append(('code', 'ilike', codes)) self.budget = Chartfield.search(dom, order='id') @api.onchange('owner_budget_filter') def _onchange_owner_budget_filter(self): self.budget = [] Chartfield = self.env['chartfield.view'] dom = [] if self.owner_budget_filter: codes = self.owner_budget_filter.split('\n') codes = [x.strip() for x in codes] codes = ','.join(codes) dom.append(('code', 'ilike', codes)) self.owner_budget = Chartfield.search(dom, order='id') @api.onchange('asset_state', 'asset_active') def _onchange_asset_state_asset_active(self): res = {} state_list = [] for rec in self.asset_state: status = rec.status state_list.append(status) if self.asset_active == 'active': res['domain'] = { 'asset_ids': [('state', 'in', state_list), ('active', '=', True)] } if self.asset_active == 'inactive': res['domain'] = { 'asset_ids': [('state', 'in', state_list), ('active', '=', False)] } return res @api.onchange('costcenter_ids') def _onchange_costcenter(self): res = {} costcenter_list = [] for rec in self.costcenter_ids: code = rec.code costcenter_list.append(code) if self.costcenter_ids: res['domain'] = { 'budget': [('code', 'in', costcenter_list)], 'owner_budget': [('code', 'in', costcenter_list)] } else: res['domain'] = { 'budget': [('active', '=', True)], 'owner_budget': [('active', '=', True)] } return res
class mail_message(models.Model): _inherit = 'mail.message' is_moved = fields.Boolean('Is moved') moved_from_res_id = fields.Integer('Related Document ID (Original)') moved_from_model = fields.Char('Related Document Model (Original)') moved_from_parent_id = fields.Many2one('mail.message', 'Parent Message (Original)', ondelete='set null') moved_by_message_id = fields.Many2one( 'mail.message', 'Moved by message', ondelete='set null', help='Top message, that initate moving this message') moved_by_user_id = fields.Many2one('res.users', 'Moved by user', ondelete='set null') all_child_ids = fields.One2many('mail.message', string='All childs', compute='_get_all_childs', help='all childs, including subchilds') @api.one def _get_all_childs(self, include_myself=True): ids = [] if include_myself: ids.append(self.id) while True: new_ids = self.search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids if new_ids: ids = ids + new_ids continue break moved_childs = self.search([('moved_by_message_id', '=', self.id)]).ids self.all_child_ids = ids + moved_childs @api.one def move(self, parent_id, res_id, model, move_back): vals = {} if move_back: # clear variables if we move everything back vals['is_moved'] = False vals['moved_by_user_id'] = None vals['moved_by_message_id'] = None vals['moved_from_res_id'] = None vals['moved_from_model'] = None vals['moved_from_parent_id'] = None else: vals['parent_id'] = parent_id vals['res_id'] = res_id vals['model'] = model vals['is_moved'] = True vals['moved_by_user_id'] = self.env.user.id vals['moved_by_message_id'] = self.id for r in self.all_child_ids: r_vals = vals.copy() if not r.is_moved: # moved_from_* variables contain not last, but original # reference r_vals['moved_from_parent_id'] = r.parent_id.id r_vals['moved_from_res_id'] = r.res_id r_vals['moved_from_model'] = r.model elif move_back: r_vals['parent_id'] = r.moved_from_parent_id.id r_vals['res_id'] = r.moved_from_res_id r_vals['model'] = r.moved_from_model print 'update message', r, r_vals r.sudo().write(r_vals) def name_get(self, cr, uid, ids, context=None): if not (context or {}).get('extended_name'): return super(mail_message, self).name_get(cr, uid, ids, context=context) if isinstance(ids, (list, tuple)) and not len(ids): return [] if isinstance(ids, (long, int)): ids = [ids] reads = self.read(cr, uid, ids, ['record_name', 'model', 'res_id'], context=context) res = [] for record in reads: name = record['record_name'] or '' extended_name = ' [%s] ID %s' % (record.get( 'model', 'UNDEF'), record.get('res_id', 'UNDEF')) res.append((record['id'], name + extended_name)) return res def _message_read_dict(self, cr, uid, message, parent_id=False, context=None): res = super(mail_message, self)._message_read_dict(cr, uid, message, parent_id, context) res['is_moved'] = message.is_moved return res
class MgmtSystemAction(models.Model): """Model class that manage action.""" _name = "mgmtsystem.action" _description = "Action" _inherit = ['mail.thread', 'ir.needaction_mixin'] def _default_company(self): """Return the user company id.""" return self.env.user.company_id def _default_owner(self): """Return the user.""" return self.env.user def _default_stage(self): """Return the default stage.""" return self.env['mgmtsystem.action.stage'].search( [('is_starting', '=', True)], limit=1) @api.model def _elapsed_days(self, dt1_text, dt2_text): res = 0 if dt1_text and dt2_text: dt1 = fields.Datetime.from_string(dt1_text) dt2 = fields.Datetime.from_string(dt2_text) res = (dt2 - dt1).days return res @api.depends('opening_date', 'create_date') def _compute_number_of_days_to_open(self): for action in self: action.number_of_days_to_close_open = action._elapsed_days( action.create_date, action.opening_date) @api.depends('date_closed', 'create_date') def _compute_number_of_days_to_close(self): for action in self: action.number_of_days_to_close_open = action._elapsed_days( action.create_date, action.date_closed) name = fields.Char('Subject', required=True) active = fields.Boolean('Active', default=True) date_deadline = fields.Date('Deadline') create_date = fields.Datetime('Create Date', readonly=True, default=fields.datetime.now()) cancel_date = fields.Datetime('Cancel Date', readonly=True) opening_date = fields.Datetime('Opening Date', readonly=True) date_closed = fields.Datetime('Closed Date', readonly=True) number_of_days_to_open = fields.Integer( '# of days to open', compute=_compute_number_of_days_to_open, store=True) number_of_days_to_close = fields.Integer( '# of days to close', compute=_compute_number_of_days_to_close, store=True) reference = fields.Char('Reference', required=True, readonly=True, default="NEW") user_id = fields.Many2one('res.users', 'Responsible', default=_default_owner, required=True) description = fields.Text('Description') type_action = fields.Selection( [('immediate', 'Immediate Action'), ('correction', 'Corrective Action'), ('prevention', 'Preventive Action'), ('improvement', 'Improvement Opportunity')], 'Response Type', required=True) system_id = fields.Many2one('mgmtsystem.system', 'System') company_id = fields.Many2one('res.company', 'Company', default=_default_company) stage_id = fields.Many2one('mgmtsystem.action.stage', 'Stage', default=_default_stage) @api.model def _stage_groups(self, present_ids, domain, **kwargs): """This method is used by Kanban view to show empty stages.""" # perform search # We search here only stage ids stage_ids = self.env['mgmtsystem.action.stage']._search([]) # We search here stages objects result = self.env['mgmtsystem.action.stage'].search([]).name_get() # restore order of the search result.sort( lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) return result, None _group_by_full = {'stage_id': _stage_groups} @api.model def _get_stage_new(self): return self.env['mgmtsystem.action.stage'].search( [('is_starting', '=', True)], limit=1) @api.model def _get_stage_open(self): return self.env.ref('mgmtsystem_action.stage_open') @api.model def _get_stage_close(self): return self.env.ref('mgmtsystem_action.stage_close') @api.model def _get_stage_cancel(self): return self.env.ref('mgmtsystem_action.stage_cancel') @api.multi def case_open(self): """ Opens case """ for case in self: case.write({'active': True, 'stage_id': case._get_stage_open().id}) return True
class TestScriptSetupActionOperation(models.Model): _name = "hc.test.script.setup.action.operation" _description = "Test Script Setup Action Operation" setup_action_id = fields.Many2one( comodel_name="hc.test.script.setup.action", string="Setup Action", help= "Setup Action associated with this Test Script Setup Action Operation." ) test_action_id = fields.Many2one( comodel_name="hc.test.script.test.action", string="Test Action", help= "Test Action associated with this Test Script Setup Action Operation.") teardown_action_id = fields.Many2one( comodel_name="hc.test.script.teardown.action", string="Teardown Action", help= "Teardown Action associated with this Test Script Setup Action Operation." ) type_id = fields.Many2one( comodel_name="hc.vs.test.script.operation.code", string="Type", help="The operation code type that will be executed.") resource_id = fields.Many2one(comodel_name="hc.vs.defined.type", string="Resource", help="Resource type.") label = fields.Char(string="Label", help="Tracking/logging operation label.") description = fields.Text(string="Description", help="Tracking/reporting operation description.") accept = fields.Selection( string="Operation Accept", selection=[("xml", "XML"), ("json", "JSON"), ("ttl", "TTL"), ("none", "None")], help= "The content-type or mime-type to use for RESTful operation in the 'Accept' header." ) content_type = fields.Selection( string="Operation Content Type", selection=[("xml", "XML"), ("json", "JSON"), ("ttl", "TTL"), ("none", "None")], help= "The content-type or mime-type to use for RESTful operation in the 'Content-Type' header." ) destination = fields.Integer(string="Destination", help="Server responding to the request.") is_encode_request_url = fields.Boolean( string="Encode Request URL", help="Whether or not to send the request url in encoded format.") origin = fields.Integer(string="Origin", help="Server initiating the request.") params = fields.Char(string="Params", help="Explicitly defined path parameters.") request_id = fields.Char(string="Request Id", help="Fixture Id of mapped request.") response_id = fields.Char(string="Response Id", help="Fixture Id of mapped response.") source_id = fields.Char( string="Source Id", help="Fixture Id of body for PUT and POST requests.") target_id = fields.Char( string="Target Id", help= "Id of fixture used for extracting the [id], [type], and [vid] for GET requests." ) url = fields.Char(string="URL", help="Request URL.") request_header_ids = fields.One2many( comodel_name="hc.test.script.setup.action.operation.request.header", inverse_name="operation_id", string="Request Headers", help="Each operation can have one ore more header elements.")
class HrEmployee(models.Model): _inherit = 'hr.employee' # def _get_chargefam(self, cr, uid, ids, field_name, arg, context): # employees = self.browse(cr, uid, ids) # res = {} # for employee in employees: # count = 0 # for child in employee.children_ids: # ages = child.age.split() # if len(ages) > 1: # if int(ages[0][:-1]) < 21: # count += 1 # res[employee.id] = count # return res @api.multi def _get_chargefam(self): for emp in self: ages_list = emp.mapped('children_ids.age') emp.chargefam = sum(int(age.split('a')[0]) < 21 for age in ages_list) @api.multi def _get_visibility(self): user_obj = self.env['res.users'] for emp in self: uid = self._uid visible = False group_ids = user_obj.browse(uid).groups_id group_user_id_user = self.env.ref('base.group_hr_user') group_user_id_manager = self.env.ref('base.group_hr_manager') if (group_user_id_user.id in [group.id for group in group_ids]) or (group_user_id_manager.id in [group.id for group in group_ids]) \ or (emp.user_id.id == uid) or (emp.parent_id.user_id.id == uid): visible = True emp.visible = visible @api.multi def _wb(self): for emp in self: if emp.birthday: emp.weekbirthday = datetime.datetime.strptime(emp.birthday, "%Y-%m-%d").strftime("%W") # TODO def attendance_action_change(self, cr, uid, ids, context=None): if not context: return {} return False @api.multi def _get_children(self): """ Get number of all children for an employee """ for emp in self: emp.children = len(emp.children_ids) matricule = fields.Char(string='Matricule', size=64) cin = fields.Char(string='CIN', size=64) cin_date = fields.Date(string='Date CIN') cin_place = fields.Char(string='Lieu CIN', size=30) chargefam = fields.Float(string='Charge Familliale', compute='_get_chargefam') visible = fields.Boolean(string='Visible',compute='_get_visibility') payment_term_id = fields.One2many(string='Mode de Paiement',comodel_name='payment.term',inverse_name='employee_id') anciennete = fields.Boolean(string='Prime anciennete',help=u'Est ce que cet employe benificie de la prime d\'anciennete') affilie = fields.Boolean(string='Affilie',help=u'Est ce qu\'on va calculer les cotisations pour cet employe') state = fields.Selection(string='State', selection=[('absent', 'Absent'), ('present', 'Present')], default='absent') children_ids = fields.One2many(string='Enfants', comodel_name='hr.employee.children', inverse_name='employee_id') mother = fields.Char(string='Mere', size=64) father = fields.Char(string='Pere', size=64) spouse = fields.Char(string='Epoux(se)', size=64) weekbirthday = fields.Char(string='Week Birthday', compute='_wb') sanction_ids = fields.One2many(string='Sanctions', comodel_name='hr.employee.sanction', inverse_name='name') qualification_ids = fields.One2many(string='Qualifications', comodel_name='hr.employee.qualification', inverse_name='employee_id') medical_ids = fields.One2many(string='Billet Medical', comodel_name='hr.employee.medical.ticket', inverse_name='employee_id') decoration_ids = fields.One2many(string='Decorations', comodel_name='hr.employee.decoration', inverse_name='employee_id') note_ids = fields.One2many(string='Note Employe', comodel_name='hr.employee.note', inverse_name='employee_id') lastjob_ids = fields.One2many(string='Ancien Emploie', comodel_name='hr.employee.last.job', inverse_name='employee_id') formation_ids = fields.One2many(string='Formation', comodel_name='hr.employee.formation', inverse_name='employee_id') aptitude_ids = fields.One2many(string='Aptitudes', comodel_name='hr.employee.aptitude', inverse_name='employee_id') #contract_ids = fields.One2many(string='Contrats',comodel_name='hr.contract',inverse_name='employee_id') children = fields.Integer(string=u'Number of childs',compute='_get_children')
class CenitDataTypeTrigger(models.Model): _name = "cenit.data_type.trigger" data_type = fields.Many2one("cenit.data_type", "Data Type") name = fields.Selection([ ("on_create", "On creation"), ("on_write", "On update"), ("on_create_or_write", "On creation or update"), ("interval", "On interval"), ("only_manual", "Only manually"), ], required=True) cron = fields.Many2one('ir.cron', string='Cron rules') cron_lapse = fields.Integer("Interval number", default=10) cron_units = fields.Selection([('minutes', 'Minutes'), ('hours', 'Hours'), ('work_days', 'Work Days'), ('days', 'Days'), ('weeks', 'Weeks'), ('months', 'Months')], string="Interval units", default='minutes') cron_restrictions = fields.Selection([("create", "Newly created"), ("update", "Newly updated"), ("all", "All")], string="Restrictions", default="all") base_action_rules = fields.Many2many('base.action.rule', string='Action Rules') last_execution = fields.Datetime() @api.one def unlink(self): if self.cron: self.cron.unlink() if self.base_action_rules: for bar in self.base_action_rules: bar.server_action_ids.unlink() self.base_action_rules.unlink() return super(CenitDataTypeTrigger, self).unlink() @api.one def sync(self): if not self.data_type.enabled: if self.cron: self.cron.unlink() if self.base_action_rules: for bar in self.base_action_rules: bar.server_action_ids.unlink() self.base_action_rules.unlink() if self.name == 'only_manual': if self.base_action_rules: for bar in self.base_action_rules: bar.server_action_ids.unlink() self.base_action_rules.unlink() elif self.cron: self.cron.unlink() if self.name == 'interval': ic_obj = self.env['ir.cron'] if self.cron: vals_ic = { 'name': 'send_%s_%s' % (self.cron_restrictions, self.data_type.model.model), 'interval_number': self.cron_lapse, 'interval_type': self.cron_units, } _logger.info("\n\nWRITE IC: %s\n", vals_ic) self.cron.write(vals_ic) else: vals_ic = { 'name': 'send_%s_%s' % (self.cron_restrictions, self.data_type.model.model), 'interval_number': self.cron_lapse, 'interval_type': self.cron_units, 'numbercall': -1, 'model': 'cenit.data_type', 'function': 'perform_scheduled_action', 'args': '(%s,)' % str(self.data_type.id) } _logger.info("\n\nCREATE IC: %s\n", vals_ic) ic = ic_obj.create(vals_ic) self.with_context(local=True).write({'cron': ic.id}) if self.base_action_rules: for bar in self.base_action_rules: bar.server_action_ids.unlink() self.base_action_rules.unlink() elif self.name in ('on_create', 'on_write', 'on_create_or_write'): ias_obj = self.env['ir.actions.server'] bar_obj = self.env['base.action.rule'] if self.base_action_rules: for bar in self.base_action_rules: bar.server_action_ids.unlink() self.base_action_rules.unlink() rules = [] action_name = 'send_one_%s_as_%s' % (self.data_type.model.model, self.data_type.cenit_root) cd = "self.pool.get('{}').browse(cr, uid, {}).trigger_flows(obj)".format( self.data_type._name, self.data_type.id) vals_ias = { 'name': action_name, 'model_id': self.data_type.model.id, 'state': 'code', 'code': cd } ias = ias_obj.create(vals_ias) vals_bar = { 'name': action_name, 'active': True, 'kind': self.name, 'model_id': self.data_type.model.id, 'server_action_ids': [(6, False, [ias.id])] } bar = bar_obj.create(vals_bar) rules.append((4, bar.id, False)) self.with_context(local=True).write({'base_action_rules': rules}) if self.cron: self.cron.unlink() return True
class AccountTaxGroup(models.Model): _name = 'account.tax.group' _order = 'sequence asc' name = fields.Char(required=True, translate=True) sequence = fields.Integer(default=10)
class AccountTax(models.Model): _name = 'account.tax' _description = 'Tax' _order = 'sequence' @api.model def _default_tax_group(self): return self.env['account.tax.group'].search([], limit=1) name = fields.Char(string='Tax Name', required=True, translate=True) type_tax_use = fields.Selection([('sale', 'Sales'), ('purchase', 'Purchases'), ('none', 'None')], string='Tax Scope', required=True, default="sale", help="Determines where the tax is selectable. Note : 'None' means a tax can't be used by itself, however it can still be used in a group.") amount_type = fields.Selection(default='percent', string="Tax Computation", required=True, oldname='type', selection=[('group', 'Group of Taxes'), ('fixed', 'Fixed'), ('percent', 'Percentage of Price'), ('division', 'Percentage of Price Tax Included')]) active = fields.Boolean(default=True, help="Set active to false to hide the tax without removing it.") company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env.user.company_id) children_tax_ids = fields.Many2many('account.tax', 'account_tax_filiation_rel', 'parent_tax', 'child_tax', string='Children Taxes') sequence = fields.Integer(required=True, default=1, help="The sequence field is used to define order in which the tax lines are applied.") amount = fields.Float(required=True, digits=(16, 4)) account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)], string='Tax Account', ondelete='restrict', help="Account that will be set on invoice tax lines for invoices. Leave empty to use the expense account.", oldname='account_collected_id') refund_account_id = fields.Many2one('account.account', domain=[('deprecated', '=', False)], string='Tax Account on Refunds', ondelete='restrict', help="Account that will be set on invoice tax lines for refunds. Leave empty to use the expense account.", oldname='account_paid_id') description = fields.Char(string='Label on Invoices', translate=True) price_include = fields.Boolean(string='Included in Price', default=False, help="Check this if the price you use on the product and invoices includes this tax.") include_base_amount = fields.Boolean(string='Affect Base of Subsequent Taxes', default=False, help="If set, taxes which are computed after this one will be computed based on the price tax included.") analytic = fields.Boolean(string="Include in Analytic Cost", help="If set, the amount computed by this tax will be assigned to the same analytic account as the invoice line (if any)") tag_ids = fields.Many2many('account.account.tag', 'account_tax_account_tag', string='Tags', help="Optional tags you may want to assign for custom reporting") tax_group_id = fields.Many2one('account.tax.group', string="Tax Group", default=_default_tax_group, required=True) _sql_constraints = [ ('name_company_uniq', 'unique(name, company_id, type_tax_use)', 'Tax names must be unique !'), ] @api.multi def unlink(self): company_id = self.env.user.company_id.id ir_values = self.env['ir.values'] supplier_taxes_id = set(ir_values.get_default('product.template', 'supplier_taxes_id', company_id=company_id)) deleted_sup_tax = self.filtered(lambda tax: tax.id in supplier_taxes_id) if deleted_sup_tax: ir_values.sudo().set_default('product.template', "supplier_taxes_id", list(supplier_taxes_id - set(deleted_sup_tax.ids)), for_all_users=True, company_id=company_id) taxes_id = set(self.env['ir.values'].get_default('product.template', 'taxes_id', company_id=company_id)) deleted_tax = self.filtered(lambda tax: tax.id in taxes_id) if deleted_tax: ir_values.sudo().set_default('product.template', "taxes_id", list(taxes_id - set(deleted_tax.ids)), for_all_users=True, company_id=company_id) return super(AccountTax, self).unlink() @api.one @api.constrains('children_tax_ids', 'type_tax_use') def _check_children_scope(self): if not all(child.type_tax_use in ('none', self.type_tax_use) for child in self.children_tax_ids): raise UserError(_('The application scope of taxes in a group must be either the same as the group or "None".')) @api.one def copy(self, default=None): default = dict(default or {}, name=_("%s (Copy)") % self.name) return super(AccountTax, self).copy(default=default) @api.model def name_search(self, name, args=None, operator='ilike', limit=80): """ Returns a list of tupples containing id, name, as internally it is called {def name_get} result format: {[(id, name), (id, name), ...]} """ args = args or [] if operator in expression.NEGATIVE_TERM_OPERATORS: domain = [('description', operator, name), ('name', operator, name)] else: domain = ['|', ('description', operator, name), ('name', operator, name)] taxes = self.search(expression.AND([domain, args]), limit=limit) return taxes.name_get() @api.model def search(self, args, offset=0, limit=None, order=None, count=False): context = self._context or {} if context.get('type'): if context.get('type') in ('out_invoice', 'out_refund'): args += [('type_tax_use', '=', 'sale')] elif context.get('type') in ('in_invoice', 'in_refund'): args += [('type_tax_use', '=', 'purchase')] if context.get('journal_id'): journal = self.env['account.journal'].browse(context.get('journal_id')) if journal.type in ('sale', 'purchase'): args += [('type_tax_use', '=', journal.type)] return super(AccountTax, self).search(args, offset, limit, order, count=count) @api.onchange('amount') def onchange_amount(self): if self.amount_type in ('percent', 'division') and self.amount != 0.0 and not self.description: self.description = "{0:.4g}%".format(self.amount) @api.onchange('account_id') def onchange_account_id(self): self.refund_account_id = self.account_id @api.onchange('price_include') def onchange_price_include(self): if self.price_include: self.include_base_amount = True def _compute_amount(self, base_amount, price_unit, quantity=1.0, product=None, partner=None): """ Returns the amount of a single tax. base_amount is the actual amount on which the tax is applied, which is price_unit * quantity eventually affected by previous taxes (if tax is include_base_amount XOR price_include) """ self.ensure_one() if self.amount_type == 'fixed': return math.copysign(self.amount, base_amount) * quantity if (self.amount_type == 'percent' and not self.price_include) or (self.amount_type == 'division' and self.price_include): return base_amount * self.amount / 100 if self.amount_type == 'percent' and self.price_include: return base_amount - (base_amount / (1 + self.amount / 100)) if self.amount_type == 'division' and not self.price_include: return base_amount / (1 - self.amount / 100) - base_amount @api.v8 def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None): """ Returns all information required to apply taxes (in self + their children in case of a tax goup). We consider the sequence of the parent for group of taxes. Eg. considering letters as taxes and alphabetic order as sequence : [G, B([A, D, F]), E, C] will be computed as [A, D, F, C, E, G] RETURN: { 'total_excluded': 0.0, # Total without taxes 'total_included': 0.0, # Total with taxes 'taxes': [{ # One dict for each tax in self and their children 'id': int, 'name': str, 'amount': float, 'sequence': int, 'account_id': int, 'refund_account_id': int, 'analytic': boolean, }] } """ if len(self) == 0: company_id = self.env.user.company_id else: company_id = self[0].company_id if not currency: currency = company_id.currency_id taxes = [] # By default, for each tax, tax amount will first be computed # and rounded at the 'Account' decimal precision for each # PO/SO/invoice line and then these rounded amounts will be # summed, leading to the total amount for that tax. But, if the # company has tax_calculation_rounding_method = round_globally, # we still follow the same method, but we use a much larger # precision when we round the tax amount for each line (we use # the 'Account' decimal precision + 5), and that way it's like # rounding after the sum of the tax amounts of each line prec = currency.decimal_places if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)): prec += 5 total_excluded = total_included = base = round(price_unit * quantity, prec) # Sorting key is mandatory in this case. When no key is provided, sorted() will perform a # search. However, the search method is overridden in account.tax in order to add a domain # depending on the context. This domain might filter out some taxes from self, e.g. in the # case of group taxes. for tax in self.sorted(key=lambda r: r.sequence): if tax.amount_type == 'group': ret = tax.children_tax_ids.compute_all(price_unit, currency, quantity, product, partner) total_excluded = ret['total_excluded'] base = ret['base'] total_included = ret['total_included'] tax_amount = total_included - total_excluded taxes += ret['taxes'] continue tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner) if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)): tax_amount = round(tax_amount, prec) else: tax_amount = currency.round(tax_amount) if tax.price_include: total_excluded -= tax_amount base -= tax_amount else: total_included += tax_amount if tax.include_base_amount: base += tax_amount taxes.append({ 'id': tax.id, 'name': tax.with_context(**{'lang': partner.lang} if partner else {}).name, 'amount': tax_amount, 'sequence': tax.sequence, 'account_id': tax.account_id.id, 'refund_account_id': tax.refund_account_id.id, 'analytic': tax.analytic, }) return { 'taxes': sorted(taxes, key=lambda k: k['sequence']), 'total_excluded': currency.round(total_excluded) if bool(self.env.context.get("round", True)) else total_excluded, 'total_included': currency.round(total_included) if bool(self.env.context.get("round", True)) else total_included, 'base': base, } @api.v7 def compute_all(self, cr, uid, ids, price_unit, currency_id=None, quantity=1.0, product_id=None, partner_id=None, context=None): currency = currency_id and self.pool.get('res.currency').browse(cr, uid, currency_id, context=context) or None product = product_id and self.pool.get('product.product').browse(cr, uid, product_id, context=context) or None partner = partner_id and self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) or None ids = isinstance(ids, (int, long)) and [ids] or ids recs = self.browse(cr, uid, ids, context=context) return AccountTax.compute_all(recs, price_unit, currency, quantity, product, partner) @api.model def _fix_tax_included_price(self, price, prod_taxes, line_taxes): """Subtract tax amount from price when corresponding "price included" taxes do not apply""" # FIXME get currency in param? incl_tax = prod_taxes.filtered(lambda tax: tax not in line_taxes and tax.price_include) if incl_tax: return incl_tax.compute_all(price)['total_excluded'] return price
class AccountJournal(models.Model): _name = "account.journal" _description = "Journal" _order = 'sequence, type, code' def _default_inbound_payment_methods(self): return self.env.ref('account.account_payment_method_manual_in') def _default_outbound_payment_methods(self): return self.env.ref('account.account_payment_method_manual_out') name = fields.Char(string='Journal Name', required=True) code = fields.Char(string='Short Code', size=5, required=True, help="The journal entries of this journal will be named using this prefix.") type = fields.Selection([ ('sale', 'Sale'), ('purchase', 'Purchase'), ('cash', 'Cash'), ('bank', 'Bank'), ('general', 'Miscellaneous'), ], required=True, help="Select 'Sale' for customer invoices journals."\ " Select 'Purchase' for vendor bills journals."\ " Select 'Cash' or 'Bank' for journals that are used in customer or vendor payments."\ " Select 'General' for miscellaneous operations journals."\ " Select 'Opening/Closing Situation' for entries generated for new fiscal years.") type_control_ids = fields.Many2many('account.account.type', 'account_journal_type_rel', 'journal_id', 'type_id', string='Account Types Allowed') account_control_ids = fields.Many2many('account.account', 'account_account_type_rel', 'journal_id', 'account_id', string='Accounts Allowed', domain=[('deprecated', '=', False)]) default_credit_account_id = fields.Many2one('account.account', string='Default Credit Account', domain=[('deprecated', '=', False)], help="It acts as a default account for credit amount") default_debit_account_id = fields.Many2one('account.account', string='Default Debit Account', domain=[('deprecated', '=', False)], help="It acts as a default account for debit amount") update_posted = fields.Boolean(string='Allow Cancelling Entries', help="Check this box if you want to allow the cancellation the entries related to this journal or of the invoice related to this journal") group_invoice_lines = fields.Boolean(string='Group Invoice Lines', help="If this box is checked, the system will try to group the accounting lines when generating them from invoices.") sequence_id = fields.Many2one('ir.sequence', string='Entry Sequence', help="This field contains the information related to the numbering of the journal entries of this journal.", required=True, copy=False) refund_sequence_id = fields.Many2one('ir.sequence', string='Refund Entry Sequence', help="This field contains the information related to the numbering of the refund entries of this journal.", copy=False) sequence = fields.Integer(help='Used to order Journals in the dashboard view') #groups_id = fields.Many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', string='Groups') currency_id = fields.Many2one('res.currency', help='The currency used to enter statement', string="Currency", oldname='currency') company_id = fields.Many2one('res.company', string='Company', required=True, index=1, default=lambda self: self.env.user.company_id, help="Company related to this journal") refund_sequence = fields.Boolean(string='Dedicated Refund Sequence', help="Check this box if you don't want to share the same sequence for invoices and refunds made from this journal", default=False) inbound_payment_method_ids = fields.Many2many('account.payment.method', 'account_journal_inbound_payment_method_rel', 'journal_id', 'inbound_payment_method', domain=[('payment_type', '=', 'inbound')], string='Debit Methods', default=lambda self: self._default_inbound_payment_methods(), help="Means of payment for collecting money. Odoo modules offer various payments handling facilities, " "but you can always use the 'Manual' payment method in order to manage payments outside of the software.") outbound_payment_method_ids = fields.Many2many('account.payment.method', 'account_journal_outbound_payment_method_rel', 'journal_id', 'outbound_payment_method', domain=[('payment_type', '=', 'outbound')], string='Payment Methods', default=lambda self: self._default_outbound_payment_methods(), help="Means of payment for sending money. Odoo modules offer various payments handling facilities, " "but you can always use the 'Manual' payment method in order to manage payments outside of the software.") at_least_one_inbound = fields.Boolean(compute='_methods_compute', store=True) at_least_one_outbound = fields.Boolean(compute='_methods_compute', store=True) profit_account_id = fields.Many2one('account.account', string='Profit Account', domain=[('deprecated', '=', False)], help="Used to register a profit when the ending balance of a cash register differs from what the system computes") loss_account_id = fields.Many2one('account.account', string='Loss Account', domain=[('deprecated', '=', False)], help="Used to register a loss when the ending balance of a cash register differs from what the system computes") # Bank journals fields bank_account_id = fields.Many2one('res.partner.bank', string="Bank Account", ondelete='restrict', copy=False) display_on_footer = fields.Boolean("Show in Invoices Footer", help="Display this bank account on the footer of printed documents like invoices and sales orders.") bank_statements_source = fields.Selection([('manual', 'Record Manually')], string='Bank Feeds') bank_acc_number = fields.Char(related='bank_account_id.acc_number') bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id') _sql_constraints = [ ('code_company_uniq', 'unique (code, name, company_id)', 'The code and name of the journal must be unique per company !'), ] @api.one @api.constrains('currency_id', 'default_credit_account_id', 'default_debit_account_id') def _check_currency(self): if self.currency_id: if self.default_credit_account_id and not self.default_credit_account_id.currency_id.id == self.currency_id.id: raise UserError(_('Configuration error!\nThe currency of the journal should be the same than the default credit account.')) if self.default_debit_account_id and not self.default_debit_account_id.currency_id.id == self.currency_id.id: raise UserError(_('Configuration error!\nThe currency of the journal should be the same than the default debit account.')) @api.one @api.constrains('type', 'bank_account_id') def _check_bank_account(self): if self.type == 'bank' and self.bank_account_id: if self.bank_account_id.company_id != self.company_id: raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % self.company_id.name) # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier. # Or they are part of a bank journal and their partner_id must be the company's partner_id. if self.bank_account_id.partner_id != self.company_id.partner_id: raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % self.company_id.name) @api.onchange('default_debit_account_id') def onchange_debit_account_id(self): if not self.default_credit_account_id: self.default_credit_account_id = self.default_debit_account_id @api.onchange('default_credit_account_id') def onchange_credit_account_id(self): if not self.default_debit_account_id: self.default_debit_account_id = self.default_credit_account_id @api.multi def unlink(self): bank_accounts = self.env['res.partner.bank'].browse() for bank_account in self.mapped('bank_account_id'): accounts = self.search([('bank_account_id', '=', bank_account.id)]) if accounts <= self: bank_accounts += bank_account ret = super(AccountJournal, self).unlink() bank_accounts.unlink() return ret @api.one def copy(self, default=None): default = dict(default or {}) default.update( code=_("%s (copy)") % (self.code or ''), name=_("%s (copy)") % (self.name or '')) return super(AccountJournal, self).copy(default) @api.multi def write(self, vals): for journal in self: if ('company_id' in vals and journal.company_id.id != vals['company_id']): if self.env['account.move'].search([('journal_id', 'in', self.ids)], limit=1): raise UserError(_('This journal already contains items, therefore you cannot modify its company.')) if ('code' in vals and journal.code != vals['code']): if self.env['account.move'].search([('journal_id', 'in', self.ids)], limit=1): raise UserError(_('This journal already contains items, therefore you cannot modify its short name.')) new_prefix = self._get_sequence_prefix(vals['code'], refund=False) journal.sequence_id.write({'prefix': new_prefix}) if journal.refund_sequence_id: new_prefix = self._get_sequence_prefix(vals['code'], refund=True) journal.refund_sequence_id.write({'prefix': new_prefix}) if 'currency_id' in vals: if not 'default_debit_account_id' in vals and self.default_debit_account_id: self.default_debit_account_id.currency_id = vals['currency_id'] if not 'default_credit_account_id' in vals and self.default_credit_account_id: self.default_credit_account_id.currency_id = vals['currency_id'] if 'bank_acc_number' in vals and not vals.get('bank_acc_number') and journal.bank_account_id: raise UserError(_('You cannot empty the account number once set.\nIf you would like to delete the account number, you can do it from the Bank Accounts list.')) result = super(AccountJournal, self).write(vals) # Create the bank_account_id if necessary if 'bank_acc_number' in vals: for journal in self.filtered(lambda r: r.type == 'bank' and not r.bank_account_id): journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id')) return result @api.model def _get_sequence_prefix(self, code, refund=False): prefix = code.upper() if refund: prefix = 'R' + prefix return prefix + '/%(range_year)s/' @api.model def _create_sequence(self, vals, refund=False): """ Create new no_gap entry sequence for every new Journal""" prefix = self._get_sequence_prefix(vals['code'], refund) seq = { 'name': vals['name'], 'implementation': 'no_gap', 'prefix': prefix, 'padding': 4, 'number_increment': 1, 'use_date_range': True, } if 'company_id' in vals: seq['company_id'] = vals['company_id'] return self.env['ir.sequence'].create(seq) @api.model def _prepare_liquidity_account(self, name, company, currency_id, type): ''' This function prepares the value to use for the creation of the default debit and credit accounts of a liquidity journal (created through the wizard of generating COA from templates for example). :param name: name of the bank account :param company: company for which the wizard is running :param currency_id: ID of the currency in wich is the bank account :param type: either 'cash' or 'bank' :return: mapping of field names and values :rtype: dict ''' # Seek the next available number for the account code code_digits = company.accounts_code_digits or 0 if type == 'bank': account_code_prefix = company.bank_account_code_prefix or '' else: account_code_prefix = company.cash_account_code_prefix or company.bank_account_code_prefix or '' for num in xrange(1, 100): new_code = str(account_code_prefix.ljust(code_digits - 1, '0')) + str(num) rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1) if not rec: break else: raise UserError(_('Cannot generate an unused account code.')) liquidity_type = self.env.ref('account.data_account_type_liquidity') return { 'name': name, 'currency_id': currency_id or False, 'code': new_code, 'user_type_id': liquidity_type and liquidity_type.id or False, 'company_id': company.id, } @api.model def create(self, vals): company_id = vals.get('company_id', self.env.user.company_id.id) if vals.get('type') in ('bank', 'cash'): # For convenience, the name can be inferred from account number if not vals.get('name') and 'bank_acc_number' in vals: vals['name'] = vals['bank_acc_number'] # If no code provided, loop to find next available journal code if not vals.get('code'): for num in xrange(1, 100): # journal_code has a maximal size of 5, hence we can enforce the boundary num < 100 journal_code = (vals['type'] == 'cash' and 'CSH' or 'BNK') + str(num) journal = self.env['account.journal'].search([('code', '=', journal_code), ('company_id', '=', company_id)], limit=1) if not journal: vals['code'] = journal_code break else: raise UserError(_("Cannot generate an unused journal code. Please fill the 'Shortcode' field.")) # Create a default debit/credit account if not given default_account = vals.get('default_debit_account_id') or vals.get('default_credit_account_id') if not default_account: company = self.env['res.company'].browse(company_id) account_vals = self._prepare_liquidity_account(vals.get('name'), company, vals.get('currency_id'), vals.get('type')) default_account = self.env['account.account'].create(account_vals) vals['default_debit_account_id'] = default_account.id vals['default_credit_account_id'] = default_account.id # We just need to create the relevant sequences according to the chosen options if not vals.get('sequence_id'): vals.update({'sequence_id': self.sudo()._create_sequence(vals).id}) if vals.get('type') in ('sale', 'purchase') and vals.get('refund_sequence') and not vals.get('refund_sequence_id'): vals.update({'refund_sequence_id': self.sudo()._create_sequence(vals, refund=True).id}) journal = super(AccountJournal, self).create(vals) # Create the bank_account_id if necessary if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'): journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id')) return journal def set_bank_account(self, acc_number, bank_id=None): """ Create a res.partner.bank and set it as value of the field bank_account_id """ self.ensure_one() self.bank_account_id = self.env['res.partner.bank'].create({ 'acc_number': acc_number, 'bank_id': bank_id, 'company_id': self.company_id.id, 'currency_id': self.currency_id.id, 'partner_id': self.company_id.partner_id.id, }).id @api.multi @api.depends('name', 'currency_id', 'company_id', 'company_id.currency_id') def name_get(self): res = [] for journal in self: currency = journal.currency_id or journal.company_id.currency_id name = "%s (%s)" % (journal.name, currency.name) res += [(journal.id, name)] return res @api.multi @api.depends('inbound_payment_method_ids', 'outbound_payment_method_ids') def _methods_compute(self): for journal in self: journal.at_least_one_inbound = bool(len(journal.inbound_payment_method_ids)) journal.at_least_one_outbound = bool(len(journal.outbound_payment_method_ids))
class MrpProduction(models.Model): _inherit = 'mrp.production' _order = 'name desc' date_planned = fields.Datetime(readonly=False) # Redefined routing_id = fields.Many2one(ondelete='restrict') # Redefined date = fields.Datetime('Creation Date', states={ 'cancel': [('readonly', True)], 'done': [('readonly', True)] }, default=fields.Datetime.now, copy=False) state = fields.Selection(PRODUCTION_STATES) # Redefined note = fields.Text('Notes') workcenter_lines = fields.One2many(readonly=False) # Redefined origin = fields.Char( readonly=False, # Redefined states={ 'cancel': [('readonly', True)], 'done': [('readonly', True)] }) color_production = fields.Integer('Color production', compute='_get_color_production', readonly=True) theo_cost = fields.Float('Theorical Cost', digits=dp.get_precision('Product Price'), copy=False) production_type = fields.Selection(PRODUCTION_TYPES, 'Type of production', default='normal', copy=False) @api.multi def _get_color_production(self): for prod in self: color_production = -1 # blanco (cero da error al cargar la vista kanban) if prod.priority == '0': # Prioridad no urgente color_production = 4 # verde claro elif prod.priority == '1': # Prioridad normal color_production = 3 # amarillo elif prod.priority == '2': # Prioridad urgente color_production = 2 # rojo claro elif prod.priority == '3': # Prioridad muy urgente color_production = 1 # gris prod.color_production = color_production @api.multi def modify_consumption(self): ctx = dict(self._context, active_model=self._name, active_ids=self.ids, active_id=self.ids[0]) mod_cons_obj = self.env['mrp.modify.consumption'].with_context(ctx) return mod_cons_obj.create({}).wizard_view() @api.model def _costs_generate(self, production): """ Calculates total costs at the end of the production. @param production: Id of production order. @return: Calculated amount. """ amount = 0.0 analytic_line_obj = self.env['account.analytic.line'] for wc_line in production.workcenter_lines: wc = wc_line.workcenter_id if wc.costs_journal_id and wc.costs_general_account_id: # Cost per hour value = wc_line.hour * wc.costs_hour account = wc.costs_hour_account_id.id if value and account: amount += value analytic_line_obj.sudo().create({ 'name': wc_line.name + ' (H)', 'amount': value, 'account_id': account, 'general_account_id': wc.costs_general_account_id.id, 'journal_id': wc.costs_journal_id.id, 'ref': wc.code, 'product_id': wc.product_id.id, 'unit_amount': wc_line.hour, 'product_uom_id': wc.product_id and wc.product_id.uom_id.id or False }) return amount @api.model def _make_production_produce_line(self, production): move_id = super(MrpProduction, self)._make_production_produce_line(production) move = self.env['stock.move'].browse(move_id) move_name = _('PROD: %s') % production.name move.write({'name': move_name}) return move_id @api.onchange('product_uos_qty') def product_uos_qty_change(self): if self.product_id.uos_id: qty_uom = float(self.product_uos_qty / (self.product_id.uos_coeff or 1.0)) self.product_qty = qty_uom self.product_uos = self.product_id.uos_id else: self.product_uos_qty = False self.product_uos = False @api.model def action_produce(self, production_id, production_qty, production_mode, wiz=False): stock_move_obj = self.env['stock.move'] uom_obj = self.env['product.uom'] production = self.browse(production_id) production_qty_uom = uom_obj._compute_qty( production.product_uom.id, production_qty, production.product_id.uom_id.id) precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') main_production_move = False default_mode = self._context.get('default_mode', False) if production_mode == 'produce': # New Case: Produce Only produced_products = {} for produced_product in production.move_created_ids2: if produced_product.scrapped: continue if not produced_products.get(produced_product.product_id.id, False): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id. id] += produced_product.product_qty for produce_product in production.move_created_ids: subproduct_factor = self._get_subproduct_factor( production.id, produce_product.id) lot_id = wiz and wiz.lot_id.id or False qty = min(subproduct_factor * production_qty_uom, produce_product.product_qty ) # Needed when producing more than maximum quantity new_moves = produce_product.action_consume( qty, location_id=produce_product.location_id.id, restrict_lot_id=lot_id) stock_move_obj.browse(new_moves).write( {'production_id': production_id}) remaining_qty = subproduct_factor * production_qty_uom - qty if not float_is_zero(remaining_qty, precision_digits=precision): # In case you need to make more than planned # consumed more in wizard than previously planned extra_move_id = produce_product.copy( default={ 'product_uom_qty': remaining_qty, 'production_id': production_id }) extra_move_id.action_confirm() extra_move_id.action_done() if produce_product.product_id == production.product_id: main_production_move = produce_product.id if default_mode != 'consume' and not production.move_created_ids: production.signal_workflow('button_finished_validated') else: if not main_production_move: main_production_move = production.move_created_ids2 and production.move_created_ids2[ 0].id # Añadimos al contexto 'main_production_move' # para poder escribirlo en el write y en el action_consume() self = self.with_context(main_production_move=main_production_move) res = super(MrpProduction, self).action_produce(production_id, production_qty, production_mode, wiz=wiz) if default_mode != 'consume' and not production.move_created_ids: production.signal_workflow('button_finished_validated') if default_mode == 'consume': # Custom behaivor, set closed state production.signal_workflow('button_validated_closed') return True @api.multi def action_finished(self): for production in self: production.write({'state': 'finished'}) return True @api.multi def action_validated(self): tmpl_obj = self.env['product.template'] for production in self: theo_cost = tmpl_obj._calc_price(production.bom_id, test=True) production.write({'state': 'validated', 'theo_cost': theo_cost}) return True @api.multi def action_close(self): tmpl_obj = self.env['product.template'] precision = self.env['decimal.precision'].precision_get( 'Product Price') for production in self: date = max([ x.date for x in production.move_created_ids2 if x.state == 'done' and not x.scrapped ] or [None]) for move in production.move_lines2.filtered( lambda r: r.state == 'done'): # Establecemos en los movimiento de consumos los precios de coste de producto que tenía en la fecha # que se realizó el producto finalizado, para que coincida con la misma posición # en la que se calcula el theo_cost. Esto es debido a que los consumos se pueden hacer más # tarde que la validación del producto terminado (action_validated) price_unit = tmpl_obj.get_history_price( move.product_id.product_tmpl_id.id, move.company_id.id, date=date) # Aplicamos el redondeo que tendría el campo standard_price, # ya que get_history_price devuelve el valor sin precision price_unit = float_round(price_unit, precision_digits=precision) price_unit = price_unit or move.product_id.standard_price move.write({'price_unit': price_unit}) production.write({'state': 'closed'}) return True @api.multi def action_cancel(self): """ Cancels the production order and related stock moves. @return: True """ res = super(MrpProduction, self).action_cancel() # Put related procurements in cancel state proc_obj = self.env['procurement.order'] procs = proc_obj.search([('production_id', 'in', self.ids)]) procs.write({'state': 'cancel'}) return res @api.multi def action_in_production(self): """ Overwrite to set startworking state of all workcenter lines instead only one. """ for workcenter_line in self.mapped('workcenter_lines'): workcenter_line.signal_workflow('button_start_working') return super(MrpProduction, self).action_in_production() @api.multi def action_production_end(self): prod_line_obj = self.env['mrp.production.product.line'] res = super(MrpProduction, self).action_production_end() for production in self: bom = production.bom_id finished_qty = sum([ x.product_uom_qty for x in production.move_created_ids2 if x.state == 'done' and not x.scrapped ]) factor = self.env['product.uom']._compute_qty( production.product_uom.id, finished_qty, bom.product_uom.id) new_qty = factor / bom.product_qty routing_id = production.routing_id.id result, result2 = self.env['mrp.bom']._bom_explode( bom, production.product_id, new_qty, routing_id=routing_id) prod_lines = result production.product_lines.unlink() for line in prod_lines: line['production_id'] = production.id prod_line_obj.create(line) # Nos aseguramos de que la trazabilidad hacia arriba de la producción es correcta # Hay casos en los que se eliminan las lineas de consumos y se agragan nuevas, # momento en el que se pierde la traza self.update_production_traceability() return res @api.multi def update_production_traceability(self): for production in self: for move in production.move_created_ids2.filtered( lambda r: r.state == 'done'): if move.production_id: # Is final production move raw_ids = move.production_id.move_lines raw_ids |= move.production_id.move_lines2.filtered( lambda r: r.state != 'cancel' and not r.scrapped) move.write({'parent_ids': [(6, 0, raw_ids.ids)]}) return True @api.multi def unlink(self): """ Unlink the production order and related stock moves. @return: True """ if any(x.state not in ('draft', 'confirmed', 'ready', 'in_production', 'cancel') for x in self): raise exceptions.Warning( _('Error!'), _('You cannot delete a production which is not cancelled.')) prods_to_cancel = self.filtered(lambda r: r.state != 'cancel') if prods_to_cancel: prods_to_cancel.action_cancel() moves_to_unlink = self.mapped('move_created_ids2') + self.mapped( 'move_lines2') moves_to_unlink.unlink() wc_lines_to_unlink = self.mapped('workcenter_lines') wc_lines_to_unlink.unlink() res = super(MrpProduction, self).unlink() return res @api.multi def update_production_priority(self): domain = [('priority', '!=', '3'), ('state', 'in', ['confirmed', 'ready'])] production_ids = self or self.search(domain) for production in production_ids: product_id = production.product_id ctx = dict(self._context, location=production.location_dest_id.id) product_available = product_id.with_context( ctx)._product_available()[product_id.id] qty_to_compare = product_available[ 'qty_available'] - product_available['outgoing_qty'] company_id = production.company_id domain = company_id and [('company_id', '=', company_id.id)] or [] domain.append(('product_id', '=', product_id.id)) op = self.env['stock.warehouse.orderpoint'].search(domain, limit=1) min_qty = security_qty = 0 if op: min_qty = min(op.product_min_qty, op.product_max_qty) security_qty = op.product_security_qty if qty_to_compare <= 0: priority = '2' # Urgente elif qty_to_compare <= security_qty: priority = '1' # Normal elif qty_to_compare <= min_qty: priority = '0' # No urgente else: priority = '0' # No urgente if production.priority != priority: production.write({'priority': priority}) return True
class MrpProductionWorkcenterLine(models.Model): _inherit = 'mrp.production.workcenter.line' _order = 'id' @api.multi def _read_group_workcenter_ids(self, domain, read_group_order=None, access_rights_uid=None): workcenter_obj = self.env['mrp.workcenter'] workcenter_line_obj = self.env['mrp.production.workcenter.line'] access_rights_uid = access_rights_uid or self._uid order = workcenter_obj._order if read_group_order == 'workcenter_id desc': order = '%s desc' % order workcenter_ids = workcenter_obj._search( [], order=order, access_rights_uid=access_rights_uid) workcenter_ids = workcenter_obj.sudo(access_rights_uid).browse( workcenter_ids) result = workcenter_ids.name_get() # restore order of the search result.sort(lambda x, y: cmp(workcenter_ids.ids.index(x[0]), workcenter_ids.ids.index(y[0]))) fold = {} for workcenter in workcenter_ids: domain = [('workcenter_id', '=', workcenter.id), ('production_state', 'in', ('ready', 'confirmed', 'in_production'))] count = workcenter_line_obj._search( domain, count=True, access_rights_uid=access_rights_uid) fold[workcenter.id] = False if count else True return result, fold _group_by_full = {'workcenter_id': _read_group_workcenter_ids} operators_ids = fields.Many2many('hr.employee', string='Operators', rel='hr_employee_mrp_prod_workc_line_rel', id1='workcenter_line_id', id2='employee_id') production_stops_ids = fields.One2many('production.stops', 'production_workcenter_line_id', 'Production stops') time_start = fields.Float('Time before prod.', help="Time in hours for the setup.") time_stop = fields.Float('Time after prod.', help="Time in hours for the cleaning.") gasoleo_start = fields.Float('Gasoleo start') gasoleo_stop = fields.Float('Gasoleo stop') color = fields.Integer('Color Index') move_id = fields.Many2one('stock.move', 'Move', related='production_id.move_prod_id', readonly=True) color_production = fields.Integer('Color production', related='production_id.color_production', readonly=True) routing_id = fields.Many2one('mrp.routing', 'Routing', related='production_id.routing_id', readonly=True) real_time = fields.Float('Real time') priority = fields.Selection([('0', 'Not urgent'), ('1', 'Normal'), ('2', 'Urgent'), ('3', 'Very Urgent')], 'Priority', related='production_id.priority', readonly=True, store=True) production_type = fields.Selection(PRODUCTION_TYPES, 'Type of production', related='production_id.production_type', readonly=True) product_uos_qty = fields.Float('Product UoS Quantity', related='production_id.product_uos_qty', readonly=True) product_uos = fields.Many2one('product.uom', 'Product UoS', related='production_id.product_uos', readonly=True) kanban_name = fields.Char('Kanban name', compute='_get_kanban_name', readonly=True) availability_ratio = fields.Float( 'Availability ratio', size=8, default=1, help="Availability ratio expected for this workcenter line. " "The estimated time was calculated according to this ratio.") workorder_planned_state = fields.Selection([('0', 'No planned'), ('1', 'Planned')], 'Planned state') production_state = fields.Selection(PRODUCTION_STATES, 'Production Status', related='production_id.state', readonly=True) @api.multi def _get_kanban_name(self): for line in self: line.kanban_name = line.production_id.name + u' - ' + ( (line.name).split('-')[0])[:-1] @api.multi def modify_production_order_state(self, action): """ Modifies production order state if work order state is changed. @param action: Action to perform. @return: Nothing """ self.ensure_one() prod = self.production_id if action == 'start': if prod.state == 'confirmed': prod.force_production() prod.signal_workflow('button_produce') elif prod.state in ('ready', 'in_production', 'finished', 'validated', 'closed'): prod.signal_workflow('button_produce') else: raise exceptions.Warning( _('Error!'), _('Manufacturing order cannot be started in state "%s"!') % (prod.state)) else: return super(MrpProductionWorkcenterLine, self).modify_production_order_state(action) return @api.multi def open_mrp_production_form(self): self.ensure_one() prod = self.production_id if not prod: return False return { 'name': 'MRP Production', 'view_mode': 'form', 'view_type': 'form', 'res_model': 'mrp.production', 'res_id': prod.id, 'type': 'ir.actions.act_window', 'nodestroy': True, 'target': 'current', 'context': self._context } @api.multi def unlink(self): if any(x.state not in ('draft', 'cancel') for x in self): raise exceptions.Warning( _('Error!'), _('You cannot delete a work order which is not in draft or cancelled.' )) res = super(MrpProductionWorkcenterLine, self).unlink() return res
class task_subject(models.Model): _name = 'task.subject' name = fields.Char('Subject') description = fields.Char('Content') alert_days = fields.Integer('Alert Before Days')
class account_vat_ledger(models.Model): _inherit = "account.vat.ledger" REGINFO_CV_ALICUOTAS = fields.Text( 'REGINFO_CV_ALICUOTAS', readonly=True, ) REGINFO_CV_COMPRAS_IMPORTACIONES = fields.Text( 'REGINFO_CV_COMPRAS_IMPORTACIONES', readonly=True, ) REGINFO_CV_CBTE = fields.Text( 'REGINFO_CV_CBTE', readonly=True, ) REGINFO_CV_CABECERA = fields.Text( 'REGINFO_CV_CABECERA', readonly=True, ) vouchers_file = fields.Binary( _('Vouchers File'), compute='get_files', readonly=True ) vouchers_filename = fields.Char( _('Vouchers Filename'), readonly=True, compute='get_files', ) aliquots_file = fields.Binary( _('Aliquots File'), compute='get_files', readonly=True ) aliquots_filename = fields.Char( _('Aliquots Filename'), readonly=True, compute='get_files', ) import_aliquots_file = fields.Binary( _('Import Aliquots File'), compute='get_files', readonly=True ) import_aliquots_filename = fields.Char( _('Import Aliquots Filename'), readonly=True, compute='get_files', ) prorate_tax_credit = fields.Boolean( 'Prorate Tax Credit', ) prorate_type = fields.Selection( [('global', 'Global'), ('by_voucher', 'By Voucher')], 'Prorate Type', ) tax_credit_computable_amount = fields.Float( 'Credit Computable Amount', ) sequence = fields.Integer( 'Sequence', default=0, required=True, help='Se deberá indicar si la presentación es Original (00) o ' 'Rectificativa y su orden' ) @api.model def format_amount(self, amount, padding=15, decimals=2, invoice=False): # get amounts on correct sign despite conifiguration on taxes and tax # codes # TODO # remove this and perhups invoice argument (we always send invoice) # for invoice refund we dont change sign (we do this before) # if invoice: # amount = abs(amount) # if invoice.type in ['in_refund', 'out_refund']: # amount = -1.0 * amount # if amount < 0: # template = "-{:0>%dd}" % (padding-1) # else: template = "{:0>%dd}" % (padding) return template.format( int(round(abs(amount) * 10**decimals, decimals))) @api.one @api.depends( 'REGINFO_CV_CBTE', 'REGINFO_CV_ALICUOTAS', 'type', # 'period_id.name' ) def get_files(self): # segun vimos aca la afip espera "ISO-8859-1" en vez de utf-8 # http://www.planillasutiles.com.ar/2015/08/ # como-descargar-los-archivos-de.html if self.REGINFO_CV_ALICUOTAS: self.aliquots_filename = _('Alicuots_%s_%s.txt') % ( self.type, self.date_to, # self.period_id.name ) self.aliquots_file = base64.encodestring( self.REGINFO_CV_ALICUOTAS.encode('ISO-8859-1')) if self.REGINFO_CV_COMPRAS_IMPORTACIONES: self.import_aliquots_filename = _('Import_Alicuots_%s_%s.txt') % ( self.type, self.date_to, # self.period_id.name ) self.import_aliquots_file = base64.encodestring( self.REGINFO_CV_COMPRAS_IMPORTACIONES.encode('ISO-8859-1')) if self.REGINFO_CV_CBTE: self.vouchers_filename = _('Vouchers_%s_%s.txt') % ( self.type, self.date_to, # self.period_id.name ) self.vouchers_file = base64.encodestring( self.REGINFO_CV_CBTE.encode('ISO-8859-1')) @api.one def compute_citi_data(self): # no lo estamos usando # self.get_REGINFO_CV_CABECERA() self.get_REGINFO_CV_CBTE() self.get_REGINFO_CV_ALICUOTAS() if self.type == 'purchase': self.get_REGINFO_CV_COMPRAS_IMPORTACIONES() @api.model def get_partner_document_code(self, partner): # TODO agregar validaciones para los que se presentan sin numero de # documento para operaciones menores a 1000 segun doc especificacion # regimen de... if partner.main_id_category_id.afip_code: return "{:0>2d}".format(partner.main_id_category_id.afip_code) else: return '99' @api.model def get_partner_document_number(self, partner): # TODO agregar validaciones para los que se presentan sin numero de # documento para operaciones menores a 1000 segun doc especificacion # regimen de... return (partner.main_id_number or '').rjust(20, '0') @api.model def get_point_of_sale(self, invoice): # this invalidate cache is to fix that when we request pos number # all invoices of the vat ledger, no matter citi export or not, # are requested to compute pos number invoice.invalidate_cache() return "{:0>5d}".format(invoice.point_of_sale_number) @api.multi def get_citi_invoices(self): self.ensure_one() return self.env['account.invoice'].search([ ('document_type_id.export_to_citi', '=', True), ('id', 'in', self.invoice_ids.ids)], order='date_invoice asc') @api.one def get_REGINFO_CV_CBTE(self): res = [] invoices = self.get_citi_invoices() invoices.check_argentinian_invoice_taxes() if self.type == 'purchase': partners = invoices.mapped('commercial_partner_id').filtered( lambda r: r.main_id_category_id.afip_code in ( False, 99) or not r.main_id_number) if partners: raise ValidationError(_( "On purchase citi, partner document is mandatory and " "partner document type must be different from 99. " "Partners %s") % partners.ids) for inv in invoices: # only vat taxes with codes 3, 4, 5, 6, 8, 9 # segun: http://contadoresenred.com/regimen-de-informacion-de- # compras-y-ventas-rg-3685-como-cargar-la-informacion/ # empezamos a contar los codigos 1 (no gravado) y 2 (exento) # si no hay alicuotas, sumamos una de esta con 0, 0, 0 en detalle # usamos mapped por si hay afip codes duplicados (ej. manual y # auto) cant_alicuotas = len(inv.vat_tax_ids.filtered( lambda r: r.tax_id.tax_group_id.afip_code in [3, 4, 5, 6, 8, 9] ).mapped('tax_id.tax_group_id.afip_code')) # iva no corresponde no suma if not cant_alicuotas and inv.vat_tax_ids.filtered( lambda r: r.tax_id.tax_group_id.afip_code in [1, 2]): cant_alicuotas = 1 row = [ # Campo 1: Fecha de comprobante fields.Date.from_string(inv.date_invoice).strftime('%Y%m%d'), # Campo 2: Tipo de Comprobante. "{:0>3d}".format(int(inv.document_type_id.code)), # Campo 3: Punto de Venta self.get_point_of_sale(inv), # Campo 4: Número de Comprobante # TODO agregar estos casos de uso # Si se trata de un comprobante de varias hojas, se deberá # informar el número de documento de la primera hoja, teniendo # en cuenta lo normado en el artículo 23, inciso a), punto # 6., de la Resolución General N° 1.415, sus modificatorias y # complementarias. # En el supuesto de registrar de manera agrupada por totales # diarios, se deberá consignar el primer número de comprobante # del rango a considerar. "{:0>20d}".format(inv.invoice_number) ] if self.type == 'sale': # Campo 5: Número de Comprobante Hasta. # TODO agregar esto En el resto de los casos se consignará el # dato registrado en el campo 4 row.append("{:0>20d}".format(inv.invoice_number)) else: # Campo 5: Despacho de importación if inv.document_type_id.code == '66': row.append( (inv.document_number or inv.number or '').rjust( 16, '0')) else: row.append(''.rjust(16, ' ')) row += [ # Campo 6: Código de documento del comprador. self.get_partner_document_code(inv.commercial_partner_id), # Campo 7: Número de Identificación del comprador self.get_partner_document_number(inv.commercial_partner_id), # Campo 8: Apellido y Nombre del comprador. inv.commercial_partner_id.name.ljust(30, ' ')[:30], # inv.commercial_partner_id.name.encode( # 'ascii', 'replace').ljust(30, ' ')[:30], # Campo 9: Importe Total de la Operación. self.format_amount(inv.amount_total, invoice=inv), # Campo 10: Importe total de conceptos que no integran el # precio neto gravado self.format_amount(inv.vat_untaxed_base_amount, invoice=inv), ] if self.type == 'sale': row += [ # Campo 11: Percepción a no categorizados self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.type == 'perception' and r.tax_id.tax_group_id.tax == 'vat' and r.tax_id.tax_group_id.application \ == 'national_taxes') ).mapped('amount')), invoice=inv), # Campo 12: Importe de operaciones exentas self.format_amount( inv.vat_exempt_base_amount, invoice=inv), ] else: row += [ # Campo 11: Importe de operaciones exentas self.format_amount( inv.vat_exempt_base_amount, invoice=inv), # Campo 12: Importe de percepciones o pagos a cuenta del # Impuesto al Valor Agregado self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.type == 'perception' and r.tax_id.tax_group_id.tax == 'vat' and r.tax_id.tax_group_id.application \ == 'national_taxes') ).mapped( 'amount')), invoice=inv), ] row += [ # Campo 13: Importe de percepciones o pagos a cuenta de # impuestos nacionales self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.type == 'perception' and r.tax_id.tax_group_id.tax != 'vat' and r.tax_id.tax_group_id.application == 'national_taxes') ).mapped('amount')), invoice=inv), # Campo 14: Importe de percepciones de ingresos brutos self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.type == 'perception' and r.tax_id.tax_group_id.application \ == 'provincial_taxes') ).mapped('amount')), invoice=inv), # Campo 15: Importe de percepciones de impuestos municipales self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.type == 'perception' and r.tax_id.tax_group_id.application == 'municipal_taxes') ).mapped('amount')), invoice=inv), # Campo 16: Importe de impuestos internos self.format_amount( sum(inv.tax_line_ids.filtered( lambda r: r.tax_id.tax_group_id.application \ == 'internal_taxes' ).mapped('amount')), invoice=inv), # Campo 17: Código de Moneda str(inv.currency_id.afip_code), # Campo 18: Tipo de Cambio self.format_amount( inv.currency_rate or inv.currency_id.with_context( date=inv.date_invoice).compute( 1., inv.company_id.currency_id), padding=10, decimals=6), # Campo 19: Cantidad de alícuotas de IVA str(cant_alicuotas), # Campo 20: Código de operación. # WARNING. segun la plantilla es 0 si no es ninguna # TODO ver que no se informe un codigo si no correpsonde, # tal vez da error inv.fiscal_position_id.afip_code or ' ', ] if self.type == 'sale': row += [ # Campo 21: Otros Tributos self.format_amount( sum(inv.tax_line_ids.filtered( lambda r: r.tax_id.tax_group_id.application \ == 'others' ).mapped('amount')), invoice=inv), # Campo 22: vencimiento comprobante (no figura en # instructivo pero si en aplicativo) para tique y factura # de exportacion no se informa (inv.document_type_id.code in ['81', '82', '83', '19'] and '00000000' or fields.Date.from_string( inv.date_due or inv.date_invoice).strftime( '%Y%m%d')), ] else: # Campo 21: Crédito Fiscal Computable if self.prorate_tax_credit: if self.prorate_type == 'global': row.append(self.format_amount(0), invoice=inv) else: # row.append(self.format_amount(0)) raise ValidationError(_( 'by_voucher not implemented yet')) else: row.append(self.format_amount(inv.vat_amount, invoice=inv)) row += [ # Campo 22: Otros Tributos self.format_amount( sum(inv.tax_line_ids.filtered(lambda r: ( r.tax_id.tax_group_id.application \ == 'others')).mapped( 'amount')), invoice=inv), # TODO implementar estos 3 # Campo 23: CUIT Emisor / Corredor # Se informará sólo si en el campo "Tipo de Comprobante" se # consigna '033', '058', '059', '060' ó '063'. Si para # éstos comprobantes no interviene un tercero en la # operación, se consignará la C.U.I.T. del informante. Para # el resto de los comprobantes se completará con ceros self.format_amount(0, padding=11, invoice=inv), # Campo 24: Denominación Emisor / Corredor ''.ljust(30, ' ')[:30], # Campo 25: IVA Comisión # Si el campo 23 es distinto de cero se consignará el # importe del I.V.A. de la comisión self.format_amount(0, invoice=inv), ] res.append(''.join(row)) self.REGINFO_CV_CBTE = '\r\n'.join(res) @api.multi def get_tax_row(self, invoice, base, code, tax_amount): self.ensure_one() inv = invoice row = [ # Campo 1: Tipo de Comprobante "{:0>3d}".format(int(inv.document_type_id.code)), # Campo 2: Punto de Venta self.get_point_of_sale(inv), # Campo 3: Número de Comprobante "{:0>20d}".format(inv.invoice_number), ] if self.type == 'sale': row += [ # Campo 4: Importe Neto Gravado self.format_amount(base, invoice=inv), # Campo 5: Alícuota de IVA. str(code).rjust(4, '0'), # Campo 6: Impuesto Liquidado. self.format_amount(tax_amount, invoice=inv), ] else: row += [ # Campo 4: Código de documento del vendedor self.get_partner_document_code( inv.commercial_partner_id), # Campo 5: Número de identificación del vendedor self.get_partner_document_number( inv.commercial_partner_id), # Campo 6: Importe Neto Gravado self.format_amount(base, invoice=inv), # Campo 7: Alícuota de IVA. str(code).rjust(4, '0'), # Campo 8: Impuesto Liquidado. self.format_amount(tax_amount, invoice=inv), ] return row @api.one def get_REGINFO_CV_ALICUOTAS(self): res = [] for inv in self.get_citi_invoices().filtered( lambda r: r.document_type_id.code != '66'): vat_taxes = inv.vat_tax_ids.filtered( lambda r: r.tax_id.tax_group_id.afip_code in [ 3, 4, 5, 6, 8, 9]) # if only exempt or no gravado, we add one line with 0, 0, 0 # no corresponde no lo llevamos if not vat_taxes and inv.vat_tax_ids.filtered( lambda r: r.tax_id.tax_group_id.afip_code in [1, 2]): res.append(''.join(self.get_tax_row(inv, 0.0, 3, 0.0))) # we group by afip_code for afip_code in vat_taxes.mapped('tax_id.tax_group_id.afip_code'): taxes = vat_taxes.filtered( lambda x: x.tax_id.tax_group_id.afip_code == afip_code) res.append(''.join(self.get_tax_row( inv, sum(taxes.mapped('base')), afip_code, sum(taxes.mapped('amount')), ))) self.REGINFO_CV_ALICUOTAS = '\r\n'.join(res) @api.one def get_REGINFO_CV_COMPRAS_IMPORTACIONES(self): res = [] for inv in self.get_citi_invoices().filtered( lambda r: r.document_type_id.code == '66'): vat_taxes = inv.vat_tax_ids.filtered( lambda r: r.tax_id.tax_group_id.afip_code in [ 3, 4, 5, 6, 8, 9]) # we group by afip_code for afip_code in vat_taxes.mapped('tax_id.tax_group_id.afip_code'): taxes = vat_taxes.filtered( lambda x: x.tax_id.tax_group_id.afip_code == afip_code) base = sum(taxes.mapped('base')) # base_amount = sum(taxes.mapped('base_amount')) amount = sum(taxes.mapped('amount')) row = [ # Campo 1: Despacho de importación. (inv.document_number or inv.number or '').rjust( 16, '0'), # Campo 2: Importe Neto Gravado self.format_amount(base, invoice=inv), # Campo 3: Alícuota de IVA str(afip_code).rjust(4, '0'), # Campo 4: Impuesto Liquidado. self.format_amount(amount, invoice=inv), ] res.append(''.join(row)) self.REGINFO_CV_COMPRAS_IMPORTACIONES = '\r\n'.join(res)
class sessionpos(models.Model): def _fun_difference(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = 0 totali = 0 totali = session.cash_register_balance_end totalf = session.cash_register_balance_end_real for order in session.order_ids: flag = False for producto in order.lines: if producto.product_id.expense_pdt: print producto.product_id.name flag = True if flag: totali -= (order.amount_total * 2) total = (totali - totalf) res[session.id] = total if total < 0: total = -total else: total = -total if session.state != 'closed': self.write(cr, uid, session.id, {'difference2': total}, context=context) self.write(cr, uid, session.id, {'money_close': totali}, context=context) self.write(cr, uid, session.id, {'money_reported': totalf}, context=context) return res def _calc_vb(self, cr, uid, ids, fields, args, context=None): res = {} flag = False for session in self.browse(cr, uid, ids, context=context): total = 0 for order in session.order_ids: flag = False for producto in order.lines: if producto.product_id.expense_pdt or producto.product_id.income_pdt: flag = True if not flag: total += order.amount_total res[session.id] = total return res def _calc_statements_total(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = 0 for st in session.statement_ids: total += st.total_entry_encoding_custom res[session.id] = total return res def _calc_isv(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = 0 for order in session.order_ids: total += order.amount_tax res[session.id] = total return res def _calc_subtotal(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = session.venta_bruta - session.isv res[session.id] = total return res def _calc_no_facturas(self, cr, uid, ids, fields, args, context=None): res = {} array = [] count = 0 for session in self.browse(cr, uid, ids, context=context): for order in session.order_ids: count += 1 array.append(order.pos_reference) if array: res[session.id] = str(count) + " facturas " + str(array[len(array) - 1]) + " A " + str(array[0]) return res def _calc_discount(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): des_total = 0 for order in session.order_ids: discount = 0 for desc in order.lines: discount += desc.price_unit * (desc.discount / 100) des_total += discount res[session.id] = des_total return res def _calc_money_incoming(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = 0 counttotal = 0 for order in session.order_ids: total2 = 0 count = 0 for desc in order.lines: if desc.product_id.income_pdt: count += 1 total2 += desc.price_subtotal_incl total += total2 counttotal += count res[session.id] = str(counttotal) + " Entrada(s) " + " Total Entradas " + str(total) return res def _calc_money_outgoing(self, cr, uid, ids, fields, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): total = 0 counttotal = 0 for order in session.order_ids: total2 = 0 count = 0 for desc in order.lines: if desc.product_id.expense_pdt: count += 1 total2 += desc.price_subtotal_incl total += total2 counttotal += count res[session.id] = str(counttotal) + " Salida(s) " + " Total Salidas " + str(total) return res def _calc_tickets(self, cr, uid, ids, name, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): res[session.id] = { 'tickets_num': 0, 'ticket_first_id': None, 'ticket_last_id': None, } if session.order_ids: res[session.id]['tickets_num'] = len(session.order_ids) res[session.id]['ticket_first_id'] = session.order_ids[-1] res[session.id]['ticket_last_id'] = session.order_ids[0] return res def summary_by_product(self, cr, uid, ids, context=None): assert len(ids) == 1, 'This option should only be used for a single id at a time.' products = {} # product_id -> data for session in self.browse(cr, uid, ids, context=context): for order in session.order_ids: for line in order.lines: id = line.product_id.id if id not in products: products[id] = {'product': line.product_id.name, 'qty': 0, 'total': 0} products[id]['qty'] += line.qty products[id]['total'] += line.price_subtotal_incl return products.values() def summary_by_tax(self, cr, uid, ids, context=None): assert len(ids) == 1, 'This option should only be used for a single id at a time.' account_tax_obj = self.pool.get('account.tax') cur_obj = self.pool.get('res.currency') res = {} # tax_id -> data for session in self.browse(cr, uid, ids, context=context): for order in session.order_ids: for line in order.lines: taxes_ids = [tax.id for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id] price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) cur = line.order_id.pricelist_id.currency_id taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, cur.id, line.qty, line.product_id.id, line.order_id.partner_id.id or False) print 'taxes', taxes for tax in taxes['taxes']: id = tax['id'] if id not in res: t = account_tax_obj.browse(cr, uid, id, context=context) tax_rule = '' if t.amount_type == 'percent': tax_rule = str(100 * t.amount) + '%' else: tax_rule = str(t.amount) res[id] = {'name': tax['name'], 'base': 0, 'tax': tax_rule, 'total': 0, } #res[id]['base'] += cur.round(tax['price_unit'] * line.qty) res[id]['base'] += cur.round(taxes['total_excluded']) res[id]['total'] += tax['amount'] # cur_obj.round(cr, uid, cur, taxes['amount']) return res.values() def _calc_tax(self, cr, uid, ids, name, args, context=None): account_tax_obj = self.pool.get('account.tax') cur_obj = self.pool.get('res.currency') res = {} for session in self.browse(cr, uid, ids, context=context): res[session.id] = {'tax_base_total': 0} for order in session.order_ids: for line in order.lines: taxes_ids = [tax for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id] price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) taxes = account_tax_obj.compute_all(cr, uid, taxes_ids, price, line.qty, product=line.product_id, partner_id=line.order_id.partner_id.id or False) cur = line.order_id.pricelist_id.currency_id res[session.id]['tax_base_total'] += taxes['total'] return res def _calc_sales(self, cr, uid, ids, name, args, context=None): res = {} for session in self.browse(cr, uid, ids, context=context): res[session.id] = {'untaxed_sales': 0} for order in session.order_ids: for line in order.lines: if not line.product_id.taxes_id: res[session.id]['untaxed_sales'] += line.price_subtotal return res _inherit = 'pos.session' cash_register_total_entry_encoding_custom = fields.Float(related='cash_register_id.total_entry_encoding_custom', string='Total Sales', readonly=True, ) cash_register_total_entry_encoding_put_in = fields.Float(related='cash_register_id.total_entry_encoding_put_in', string='Cash put in', readonly=True, ) cash_register_total_entry_encoding_take_out = fields.Float(related='cash_register_id.total_entry_encoding_take_out', string='Cash take out', readonly=True, ) #'validate':fields.Boolean(string="Validation",help="validation"), #'difference':fields.Function(_fun_difference,string="Difference"), #'difference2':fields.Float('difference2'), #'venta_bruta':fields.Function(_calc_vb,'Venta bruta', help='Gross sales'), #'isv':fields.Function(_calc_isv,'ISV'), #'subtotal':fields.Function(_calc_subtotal,'subtotal'), #'nro_facturas':fields.Char(compute="_calc_no_facturas",'nro facturas',), #'discount':fields.Function(_calc_discount,'discount'), #'tax_base_total':fields.Function(_calc_tax,'Total Sales without taxes',), untaxed_sales = fields.Float(compute=_calc_sales, string='Untaxed sales',) #'money_incoming':fields.Char(compute="_calc_money_incoming",'money incoming',), #'money_outgoing':fields.Char(compute="_calc_money_outgoing",'money outgoing',), statements_total = fields.Float(compute=_calc_statements_total, string='Total Payments Received') tickets_num = fields.Integer(compute="_calc_tickets", string='Number of Tickets',) ticket_first_id = fields.Many2one('pos.order', compute="_calc_tickets", string='First Ticket',) ticket_last_id = fields.Many2one('pos.order', compute="_calc_tickets", string='Last Ticket',)
class MrpProduction(models.Model): _inherit = "mrp.production" goods_request_date = fields.Date('Request date') goods_return_date = fields.Date('Return date') picking_notes = fields.Text('Picking notes') hoard_ids = fields.One2many('stock.picking', string='hoards', compute='_get_hoard_picking') hoard_len = fields.Integer('hoard len', compute='_get_hoard_len') hoard_need_assignment = fields.Boolean('Hoard needs assignement', compute='_get_hoard_assigned') workcenter_lines = fields.One2many(readonly=False) @api.one @api.depends('hoard_ids') def _get_hoard_len(self): self.hoard_len = len(self.hoard_ids) @api.one @api.depends('hoard_ids') def _get_hoard_assigned(self): need_assignement = False for hoard in self.hoard_ids: if hoard.state in ('confirmed', 'partially_available'): need_assignement = True self.hoard_need_assignment = need_assignement @api.one @api.depends('move_lines.move_orig_ids', 'move_lines2.move_orig_ids') def _get_hoard_picking(self): pickings = self.env['stock.picking'] pickings += self.mapped('move_lines.move_orig_ids.picking_id').sorted( ) | self.mapped('move_lines2.move_orig_ids.picking_id').sorted() self.hoard_ids = pickings @api.multi def action_assign_hoard(self): for prod in self: prod.hoard_ids.action_assign() def _create_previous_move(self, cr, uid, move_id, product, source_location_id, dest_location_id, context=None): if not context: context = {} proc_obj = self.pool.get('procurement.group') move = super(MrpProduction, self)._create_previous_move(cr, uid, move_id, product, source_location_id, dest_location_id, context) prod_name = context.get('production', False) move_dict = {'workcenter_id': context.get('workcenter_id', False)} if prod_name: procurement = proc_obj.search(cr, uid, [('name', '=', prod_name)], context=context) if not procurement: procurement = proc_obj.create(cr, uid, {'name': prod_name}, context) else: procurement = procurement[0] move_dict['group_id'] = procurement self.pool.get('stock.move').write(cr, uid, move, move_dict, context=context) return move @api.multi def get_hoard(self): action = self.env.ref('stock.action_picking_tree') if not action: return action = action.read()[0] res = self.env.ref('stock.view_picking_form') action['views'] = [(res.id, 'form')] action['res_id'] = self.hoard_ids and self.hoard_ids[0].id or False action['context'] = False return action def action_cancel(self, cr, uid, ids, context=None): """ Cancels the production order and related stock moves. @return: True """ if context is None: context = {} move_obj = self.pool.get('stock.move') proc_obj = self.pool.get('procurement.order') for production in self.browse(cr, uid, ids, context=context): if production.move_created_ids: move_obj.action_cancel( cr, uid, [x.id for x in production.move_created_ids]) moves = move_obj.search( cr, uid, [('move_dest_id', 'in', [x.id for x in production.move_lines])], context=context) if moves: move_ids = [] for move in move_obj.browse(cr, uid, moves, context): if move.state not in ('cancel', 'done'): move_ids.append(move.id) move_obj.action_cancel(cr, uid, move_ids, context=context) move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines]) self.write(cr, uid, ids, {'state': 'cancel'}) # Put related procurements in exception proc_obj = self.pool.get("procurement.order") procs = proc_obj.search(cr, uid, [('production_id', 'in', ids)], context=context) if procs: proc_obj.write(cr, uid, procs, {'state': 'exception'}, context=context) return True @api.model def _make_consume_line_from_data(self, production, product, uom_id, qty, uos_id, uos_qty): my_context = dict(self.env.context) my_context['production'] = production.name return super( MrpProduction, self.with_context(my_context))._make_consume_line_from_data( production, product, uom_id, qty, uos_id, uos_qty) def _make_production_consume_line(self, cr, uid, line, context=None): context = dict(context) context['workcenter_id'] = line.workcenter_id.id move_id = super(MrpProduction, self)._make_production_consume_line( cr, uid, line, context) self.pool.get('stock.move').write( cr, uid, move_id, {'workcenter_id': line.workcenter_id.id}, context) return move_id @api.multi def create_continuation(self): protocol_type = self.env['protocol.type'].search([('is_continuation', '=', True)]) if not protocol_type: raise exceptions.Warning(_('Protocol error'), _('continuation protocol type not found')) assert len(protocol_type.workcenter_ids) == 1 workcenter_line_dict = { 'name': protocol_type.name + ' ' + date.today().strftime('%d-%m-%Y') + ' - ' + self.product_id.name, 'production_id': self.id, 'workcenter_id': protocol_type.workcenter_ids[0].id, 'date_planned': date.today(), 'continuation': True } self.env['mrp.production.workcenter.line'].create(workcenter_line_dict)
class PricelistOffer(models.Model): _name = 'product.pricelist.item.offer' name = fields.Char(string='Offer Name') paid_qty = fields.Integer(string='Paid quantity') free_qty = fields.Integer(string='Free quantity')
class RMAConfigSettings(models.TransientModel): _name = 'rma.config.settings' _inherit = 'res.config.settings' @api.constrains("priority_maximum", "priority_maximum") def _check_priority_config(self): for company_id in self: priority_max = company_id.priority_maximum priority_min = company_id.priority_minimum if priority_min <= 0 or priority_max <= 0: raise ValidationError( _("Priority maximum and priority_minimum must " "be greater than zero")) if priority_max >= priority_min: raise ValidationError( _("Priority maximum must be less than priority_minimum")) @api.constrains("limit_days") def _check_limit_days_config(self): company_ids = self.filtered(lambda r: r.limit_days <= 0) if company_ids: raise ValidationError(_("Limit days must be greater than zero")) limit_days = fields.Integer( help="Limit days for resolving a claim since its creation date.") priority_maximum = fields.Integer( help="Priority of a claim should be:\n" "- Very High: Purchase date <= priority maximum range.\n" "- High: priority maximum range < invoice date <= " "priority minimun range") priority_minimum = fields.Integer( help="Priority of a claim should be:\n" "- High: priority maximum range < invoice date " "<= priority minimun range.\n" "- Normal: priority minimun range < invoice date") @api.multi def get_default_rma_values(self): """Get the current company rma configuration and show into the config wizard. @return dictionary with the values to display. """ company_id = self.env.user.company_id return { "limit_days": company_id.limit_days, "priority_maximum": company_id.priority_maximum, "priority_minimum": company_id.priority_minimum, } @api.multi def set_rma_config(self): """Write the rma configuratin in the wizard into the company model. @return True """ company_id = self.env.user.company_id for rma_config in self: company_id.write({ "limit_days": rma_config.limit_days, "priority_maximum": rma_config.priority_maximum, "priority_minimum": rma_config.priority_minimum, }) return True
class employee(models.Model): """ Employee """ _name = 'employee' _description = 'Employee' @api.multi @api.depends('name') def name_get(self): """ On affiche prenom nom """ result = [] for employee_rcs in self: name = '%s %s' % (employee_rcs.first_name, employee_rcs.name) result.append((employee_rcs.id, name)) return result @api.model def name_search(self, name, args=None, operator='ilike', limit=1000): """ Fonction name_search """ recs = self.search( ['|', ('name', operator, name), ('first_name', 'ilike', name)] + args, limit=limit) return recs.name_get() @api.model def _state_get(self): return [ ('future', _('Future')), ('active', _('Active')), ('old', _('Old')), ] @api.one def _get_picture_binary_filesystem(self): attachment_obj = self.env['ir.attachment'] attachment_rs = attachment_obj.search([('res_model', '=', self._name), ('res_id', '=', self.id), ('binary_field', '=', 'picture') ]) if attachment_rs: self['picture'] = attachment_rs[0].datas @api.one def _set_picture_binary_filesystem(self): attachment_obj = self.env['ir.attachment'] attachment_rs = attachment_obj.search([('res_model', '=', self._name), ('res_id', '=', self.id), ('binary_field', '=', 'picture'), ('is_binary_field', '=', True)]) if self.picture: if attachment_rs: attachment_rs.datas = self.picture else: attachment_obj.create({ 'res_model': self._name, 'res_id': self.id, 'name': 'picture datas', 'is_binary_field': True, 'binary_field': 'picture', 'datas': self.picture, 'datas_fname': 'picture datas' }) else: attachment_rs.unlink() @api.model def _family_situation_get(self): return [ ('single', _('Single')), ('married', _('Married')), ('divorced', _('Divorced')), ('widowed', _('Widowed')), ] @api.model def _type_sex_get(self): return [ ('female', _('Female')), ('male', _('Male')), ] @api.one @api.depends('birth_date') def _compute_age(self): age = 0 if self.birth_date: age = relativedelta(datetime.now(), datetime.strptime(self.birth_date, "%Y-%m-%d")).years self.age = age #=========================================================================== # COLUMNS #=========================================================================== # Entete name = fields.Char(required=True, size=256) state = fields.Selection('_state_get', string='State', default='future', required=True) first_name = fields.Char(string="First name", required=True, size=256) resource_id = fields.Many2one('mrp.resource', string='Resource', required=False, ondelete='restrict') account_id = fields.Many2one('account.account', string='Account', required=True, ondelete='restrict') company_id = fields.Many2one('res.company', string='Company', required=True, ondelete='restrict', default=lambda self: self.env.user.company_id) picture = fields.Binary(string='Picture', compute='_get_picture_binary_filesystem', inverse='_set_picture_binary_filesystem', help='help') is_responsible = fields.Boolean(string='Responsible', default=False) calendar_id = fields.Many2one( 'calendar', string='Calendar', required=True, ondelete='restrict', help='Come from the selected resource or manually selected') category_id = fields.Many2one('employee.category', string='Category', required=True, ondelete='restrict') # Information personnelle address_id = fields.Many2one('address', string='Address', required=True, ondelete='restrict') age = fields.Integer(string='Age', compute='_compute_age') nationality_id = fields.Many2one('res.country', string='Nationality', required=False, ondelete='restrict') civility_id = fields.Many2one('res.partner.title', string='Civility', required=False, ondelete='restrict') phone = fields.Char(string='Phone', size=20, required=False) email = fields.Char(string='Email', size=128, required=False) identity_number = fields.Char(string='Identity number', size=128, required=False) passport_number = fields.Char(string='Passport number', size=128, required=False) birth_date = fields.Date(string='Birth date') account_bank_id = fields.Many2one('res.partner.bank', string='Account bank', required=False, ondelete='restrict') place_birth = fields.Char(string='Place of birth', size=256, required=False) contact_name = fields.Char(string='Contact name', size=256, required=False) relationship_contact = fields.Char(string='Relationship with the contact', size=256, required=False) contact_phone = fields.Char(string='Contact phone', size=20, required=False) specific_note_contact = fields.Text(string='Specific note contact') family_situation = fields.Selection('_family_situation_get', string='Family situation') type_sex = fields.Selection('_type_sex_get', string='Type of sex') children_ids = fields.One2many('employee.children', 'employee_id', string='Children') # Information RH entry_date = fields.Date(string='Entry date') release_date = fields.Date(string='Release date') employee_number = fields.Char(string='Employee number', size=256, required=False) degree_id = fields.Many2one('employee.degree', string='Degree', required=False, ondelete='restrict') office_id = fields.Many2one('employee.office', string='Office', required=False, ondelete='restrict') responsible_id = fields.Many2one('employee', string='Responsible', required=False, ondelete='restrict', domain=[('is_responsible', '=', True)]) service_id = fields.Many2one('employee.service', string='Service', required=False, ondelete='restrict') note_hr = fields.Text(string='Note HR') avg_hour = fields.Float( string='Average hours', default=0.0, required=False, help= "The average work hours of the employee (used to help for input the holidays )" ) #=========================================================================== # Contraintes #=========================================================================== @api.one @api.constrains('resource_id', 'calendar_id') def _check_calendar_resource(self): """ Si l'employé est lié à une resource, son calendrier doit être le même que celui de la ressource """ if self.resource_id: if self.calendar_id != self.resource_id.calendar_id: raise Warning( _("If your employee is linked to a resource, he must have the same calendar than the resource" )) #=========================================================================== # Onchanges #=========================================================================== @api.onchange('resource_id') def _onchange_resource_id(self): """ On ramène le calendrier de la resource sélectionnée """ calendar_id = False if self.resource_id: calendar_id = self.resource_id.calendar_id and self.resource_id.calendar_id.id or False self.calendar_id = calendar_id #=========================================================================== # Fonction #=========================================================================== @api.model def create(self, vals): """ Test pour ne pas avoir deux employés avec la même resource sauf si old """ employee_rcs = super(employee, self).create(vals) if employee_rcs.resource_id: employee_search_rcs = self.search([('resource_id', '=', employee_rcs.resource_id.id), ('state', '!=', 'old'), ('id', '!=', employee_rcs.id)]) if employee_search_rcs: raise except_orm( _('Error'), _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)." ) % (employee_search_rcs[0].first_name, employee_search_rcs[0].name)) return employee_rcs @api.multi def write(self, vals): """ Test pour ne pas avoir deux employés avec la même resource sauf si old """ for employee_rc in self: if vals and 'resource_id' in vals and vals['resource_id'] and ( ('state' not in vals and employee_rc.state != 'old') or ('state' in vals and vals['state'] != 'old')): if len(self.ids) > 1: raise except_orm( _('Error'), _('It is not possible to have more employees with the same resource with different old of state' )) employee_rcs = self.search([('resource_id', '=', vals['resource_id']), ('state', '!=', 'old')]) if employee_rcs: raise except_orm( _('Error'), _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)." ) % (employee_rcs[0].first_name, employee_rcs[0].name)) elif 'state' in vals and vals['state'] != 'old': employee_rcs = self.search([('resource_id', '=', employee_rc.resource_id.id), ('state', '!=', 'old'), ('id', '!=', employee_rc.id)]) if employee_rcs: raise except_orm( _('Error'), _("Employee already using this resource, you must change its status to 'old' before creating a new employee with this resource (%s %s)." ) % (employee_rcs[0].first_name, employee_rcs[0].name)) return super(employee, self).write(vals)
class clv_batch_category(models.Model): _name = 'clv_batch.category' name = fields.Char('Category', required=True, size=64, translate=True) parent_id = fields.Many2one('clv_batch.category', 'Parent Category', select=True, ondelete='restrict') code = fields.Char ('Category Code',size=128, required=False) description = fields.Char(string='Description', size=256) notes = fields.Text(string='Notes') complete_name = fields.Char(string='Full Category', compute='_name_get_fnc', store=False, readonly=True) child_ids = fields.One2many('clv_batch.category', 'parent_id', 'Child Categories') active = fields.Boolean('Active', help="If unchecked, it will allow you to hide the category without removing it.", default=1) parent_left = fields.Integer('Left parent', select=True) parent_right = fields.Integer('Right parent', select=True) batch_ids = fields.Many2many('clv_batch', 'clv_batch_category_rel', 'category_id', 'batch_id', 'Batches') _sql_constraints = [ ('uniq_category_code', 'unique(code)', "Error! The Category Code must be unique!"), ] _constraints = [ (models.Model._check_recursion, 'Error! You can not create recursive categories.', ['parent_id']) ] _parent_store = True _parent_order = 'name' _order = 'parent_left' @api.multi def name_get(self): """Return the category's display name, including their direct parent by default. :param dict context: the ``category_display`` key can be used to select the short version of the category (without the direct parent), when set to ``'short'``. The default is the long version.""" if self._context is None: self._context = {} if self._context.get('category_display') == 'short': return super(clv_category, self).name_get() if isinstance(self._ids, (int, long)): self._ids = [self._ids] reads = self.read(['name', 'parent_id']) res = [] for record in reads: name = record['name'] if record['parent_id']: name = record['parent_id'][1] + ' / ' + name res.append((record['id'], name)) return res @api.model def name_search(self, name, args=None, operator='ilike', limit=100): args = args or [] if name: name = name.split(' / ')[-1] args = [('name', operator, name)] + args categories = self.search(args, limit=limit) return categories.name_get() @api.multi def _name_get_fnc(self, field_name, arg): return dict(self.name_get()) @api.one def _name_get_fnc(self): self.refresh_complete_name = 0 complete_name = self.name_get() if complete_name: self.complete_name = complete_name[0][1] else: self.complete_name = self.name
class ResPartner(models.Model): _inherit = "res.partner" @api.multi @api.depends('capital_certificate_ids') def _compute_capital_certificate_count(self): for partner in self: partner.capital_certificate_count = len( partner.capital_certificate_ids) capital_certificate_ids = fields.One2many( string="Capital Certificates", comodel_name="capital.certificate", inverse_name="partner_id") capital_certificate_count = fields.Integer( string="Capital Certificates count", compute="_compute_capital_certificate_count") @api.multi def generate_certificate(self, year=False, send_mail=False): if not year: return False aml_obj = self.env['account.move.line'] cc_obj = self.env['capital.certificate'] mail_template = self.env.ref( "coop_capital_certificate.capital_certificate_mail_template") min_date = "%s-01-01" % (year) max_date = "%s-01-01" % (year + 1) cfc_obj = self.env['capital.fundraising.category'] account_list = tuple( [c.capital_account_id.id for c in cfc_obj.search([])]) for partner in self: lines = [] aml_ids = aml_obj.search([ ('partner_id', '=', partner.id), ('date', '>=', min_date), ('date', '<', max_date), ('account_id', 'in', account_list), ('credit', '>', 0), ], order='account_id') for aml in aml_ids: price = aml.product_id.list_price qty = aml.credit / price lines.append({ 'account_move_line_id': aml.id, 'date': aml.invoice_id.date_invoice, 'qty': qty, 'product': aml.product_id.name, 'price': price, 'payment_date': aml.date, }) lines = map(lambda x: (0, 0, x), lines) cc = cc_obj.create({ 'partner_id': partner.id, 'year': year, 'template_id': mail_template.id, 'line_ids': lines, }) cc.create_certificate(send_mail)
class StockInformation(models.Model): _name = 'stock.information' _description = 'Stock information' _order = 'company, location, product, first_day_week asc' @api.multi def _compute_week(self): orderpoint_obj = self.env['stock.warehouse.orderpoint'] proc_obj = self.env['procurement.order'] move_obj = self.env['stock.move'] pur_line_obj = self.env['purchase.order.line'] sale_line_obj = self.env['sale.order.line'] for line in self: line.qty_available = 0 line.minimum_rule = 0 if line.product and line.location: cond = [('company_id', '=', line.company.id), ('product_id', '=', line.product.id), ('location_id', '=', line.location.id), ('active', '=', True)] rule = orderpoint_obj.search(cond, limit=1) if rule: line.minimum_rule = rule.product_min_qty if line.first_week: prod = self.env['product.product'].with_context({ 'location': line.location.id }).browse(line.product.id) line.qty_available = prod.qty_available else: year = line.year week = line.week - 1 if line.week == 1: year -= 1 new_date = str(year) + '-12-31' new_date = fields.Datetime.from_string(new_date).date() week = new_date.strftime('%W') cond = [('company', '=', line.company.id), ('year', '=', year), ('week', '=', week), ('location', '=', line.location.id), ('product', '=', line.product.id)] prev = self.search(cond, limit=1) if (prev.stock_availability >= prev.outgoing_pending_amount): line.qty_available = (prev.stock_availability + line.minimum_rule - prev.outgoing_pending_amount) else: line.qty_available = line.minimum_rule if line.first_week: moves = move_obj._find_moves_from_stock_information( line.company, line.last_day_week, products=[line.product.id], location_dest_id=line.location) else: moves = move_obj._find_moves_from_stock_information( line.company, line.last_day_week, products=[line.product.id], from_date=line.first_day_week, location_dest_id=line.location) line.incoming_pending_amount = sum(moves.mapped('product_uom_qty')) line.incoming_pending_moves = [(6, 0, moves.ids)] moves = moves.filtered(lambda x: x.purchase_line_id) purchase_orders = self.env['purchase.order'] purchase_orders |= moves.mapped('purchase_line_id.order_id') line.incoming_pending_purchases = [(6, 0, purchase_orders.ids)] if line.first_week: moves = move_obj._find_moves_from_stock_information( line.company, line.last_day_week, products=[line.product.id], location_id=line.location) else: moves = move_obj._find_moves_from_stock_information( line.company, line.last_day_week, products=[line.product.id], from_date=line.first_day_week, location_id=line.location) line.outgoing_pending_amount = sum(moves.mapped('product_uom_qty')) line.outgoing_pending_moves = [(6, 0, moves.ids)] states = ['confirmed', 'exception'] if line.first_week: procs = proc_obj._find_procurements_from_stock_information( line.company, line.last_day_week, states=states, products=[line.product.id], location_id=line.location) else: procs = proc_obj._find_procurements_from_stock_information( line.company, line.last_day_week, states=states, from_date=line.first_day_week, products=[line.product.id], location_id=line.location) line.demand = sum(procs.mapped('product_qty')) procurement_orders = self.env['procurement.order'] if procs: procurement_orders |= procs line.demand_procurements = [(6, 0, procurement_orders.ids)] if line.first_week: purchase_lines = ( pur_line_obj._find_purchase_lines_from_stock_information( line.company, line.last_day_week, line.product, line.location)) else: purchase_lines = ( pur_line_obj._find_purchase_lines_from_stock_information( line.company, line.last_day_week, line.product, line.location, from_date=line.first_day_week)) line.draft_purchases_amount = sum( purchase_lines.mapped('product_qty')) purchase_orders = self.env['purchase.order'] if purchase_lines: purchase_orders |= purchase_lines.mapped('order_id') line.draft_purchases = [(6, 0, purchase_orders.ids)] if line.first_week: sale_lines = ( sale_line_obj._find_sale_lines_from_stock_information( line.company, line.last_day_week, line.product, line.location)) else: sale_lines = ( sale_line_obj._find_sale_lines_from_stock_information( line.company, line.last_day_week, line.product, line.location, from_date=line.first_day_week)) line.draft_sales_amount = sum(sale_lines.mapped('product_uom_qty')) sale_orders = self.env['sale.order'] if sale_lines: sale_orders |= sale_lines.mapped('order_id') line.draft_sales = [(6, 0, sale_orders.ids)] line.stock_availability = (line.qty_available - line.minimum_rule + line.incoming_pending_amount) if line.stock_availability >= line.outgoing_pending_amount: line.virtual_stock = 0 else: line.virtual_stock = (line.outgoing_pending_amount - line.stock_availability) @api.multi @api.depends('product', 'product.seller_ids') def _compute_product_info(self): for line in self: sequence = False for supplier in line.product.seller_ids: if not sequence or sequence and sequence > supplier.sequence: sequence = supplier.sequence line.supplier = supplier.name.id company = fields.Many2one(comodel_name='res.company', string='Company', select=True) year = fields.Integer(string='Year', select=True) week = fields.Integer(string='Week', select=True) first_week = fields.Boolean(string='First week', default=False) first_day_week = fields.Date(string='First day on week') last_day_week = fields.Date(string='Last day on week') location = fields.Many2one(comodel_name='stock.location', string='Location', translate=True, select=True) product = fields.Many2one(comodel_name='product.product', string='Product', translate=True, select=True) category = fields.Many2one(comodel_name='product.category', string='category', store=True, related='product.categ_id') product_template = fields.Many2one(comodel_name='product.template', string='Product template', store=True, related='product.product_tmpl_id') route = fields.Many2one('stock.location.route', 'Product Type') supplier = fields.Many2one('res.partner', 'Supplier', compute='_compute_product_info', store=True) qty_available = fields.Float( string='Quantity On Hand', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Initial stock') minimum_rule = fields.Float( string='Minimum rule', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Minimum rule') incoming_pending_amount = fields.Float( 'Incoming pending amount', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Incoming pending') incoming_pending_purchases = fields.Many2many( comodel_name='purchase.order', relation='rel_stock_info_incoming_pending_purchase', column1='stock_info_id', column2='purchase_id', string='Purchases', compute='_compute_week') incoming_pending_moves = fields.Many2many( comodel_name='stock.move', string='Moves incoming to date', relation='rel_stock_info_incoming_pending_move', column1='stock_info_id', column2='move_in_id', compute='_compute_week') stock_availability = fields.Float( 'Stock availability (DPS)', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Stock availability') demand = fields.Float('Demand (D)', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Demand') demand_required_run = fields.Float( 'Procurements required run', related='demand', digits=dp.get_precision('Product Unit of Measure'), store=True) demand_procurements = fields.Many2many( comodel_name='procurement.order', string='Demand procurements', relation='rel_stock_info_demand_procurement', compute='_compute_week', column1='stock_info_id', column2='proc_id') draft_purchases_amount = fields.Float( 'Draft purchases amount (INFO)', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Draft purchases amount') draft_purchases = fields.Many2many( comodel_name='purchase.order', string='Draft purchases', relation='rel_stock_info_draft_purchase', compute='_compute_week', column1='stock_info_id', column2='purchase_id') draft_sales_amount = fields.Float( 'Draft sales amount (INFO)', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Draft sales amount') draft_sales = fields.Many2many(comodel_name='sale.order', string='Draft sales', relation='rel_stock_draft_sale', compute='_compute_week', column1='stock_info_id', column2='sale_id') outgoing_pending_amount = fields.Float( 'Outgoing pending amount', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Gross requirement') outgoing_pending_moves = fields.Many2many( comodel_name='stock.move', string='Moves outgoing to date', relation='rel_stock_info_outgoing_pending_moves', column1='stock_info_id', column2='move_out_id', compute='_compute_week') virtual_stock = fields.Float( 'Virtual stock', compute='_compute_week', digits=dp.get_precision('Product Unit of Measure'), help='Net requirement') virtual_stock_required_increase = fields.Float( 'Virtual stock required increment', related='virtual_stock', digits=dp.get_precision('Product Unit of Measure'), store=True) def _calculate_first_day_week(self, date): found = False if date.weekday() == 0 or (date.day == 1 and date.month == 1): found = True while not found: date = date + relativedelta(days=-1) if date.weekday() == 0 or (date.day == 1 and date.month == 1): found = True return date.strftime('%Y-%m-%d') def _calculate_last_day_week(self, date): found = False if date.weekday() == 6 or (date.day == 31 and date.month == 12): found = True while not found: date = date + relativedelta(days=+1) if date.weekday() == 6 or (date.day == 31 and date.month == 12): found = True return date.strftime('%Y-%m-%d') def _generate_stock_information(self, wiz, product_datas): buy_route = self.env.ref('purchase.route_warehouse0_buy') for data in product_datas: datos_array = product_datas[data] from_date = fields.Date.context_today(self) from_date = self._calculate_first_day_week( fields.Datetime.from_string(from_date).date()) from_date = fields.Date.from_string(from_date) to_date = self._calculate_last_day_week( fields.Datetime.from_string(wiz.to_date).date()) to_date = fields.Date.from_string(to_date) first_week = True while from_date <= to_date: first = self._calculate_first_day_week(from_date) last = self._calculate_last_day_week(from_date) route_id = False if (datos_array['product'].route_ids and buy_route.id in datos_array['product'].route_ids.ids): route_id = buy_route.id vals = { 'company': wiz.company.id, 'location': datos_array['location'].id, 'product': datos_array['product'].id, 'route': route_id, 'year': from_date.year, 'week': from_date.strftime('%W'), 'first_day_week': first, 'last_day_week': last, 'first_week': first_week } if first_week: vals['first_day_week'] = fields.Date.context_today(self) first_week = False self.create(vals) from_date = fields.Date.to_string(from_date + relativedelta(days=7)) from_date = fields.Date.from_string(from_date) @api.multi def show_incoming_pending_purchases(self): self.ensure_one() return { 'name': _('Purchase orders'), 'view_type': 'form', "view_mode": 'tree,form,graph,calendar', 'res_model': 'purchase.order', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.incoming_pending_purchases.ids)] } @api.multi def show_incoming_pending_moves(self): self.ensure_one() return { 'name': _('Incoming pending stock moves'), 'view_type': 'form', "view_mode": 'tree,form', 'res_model': 'stock.move', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.incoming_pending_moves.ids)] } @api.multi def show_outgoing_pending_moves(self): self.ensure_one() return { 'name': _('Outgoing pending stock moves'), 'view_type': 'form', "view_mode": 'tree,form', 'res_model': 'stock.move', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.outgoing_pending_moves.ids)] } @api.multi def show_demand_procurements(self): self.ensure_one() return { 'name': _('Procurement orders in draft state'), 'view_type': 'form', "view_mode": 'tree,form', 'res_model': 'procurement.order', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.demand_procurements.ids)] } @api.multi def show_draft_purchases(self): self.ensure_one() return { 'name': _('Purchase orders in draft state'), 'view_type': 'form', "view_mode": 'tree,form,graph,calendar', 'res_model': 'purchase.order', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.draft_purchases.ids)] } @api.multi def show_draft_sales(self): self.ensure_one() return { 'name': _('Sale orders in draft state'), 'view_type': 'form', "view_mode": 'tree,form,calendar,graph', 'res_model': 'sale.order', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.draft_sales.ids)] }
class wizard(models.TransientModel): _name = 'mail_move_message.wizard' def _model_selection(self): selection = [] config_parameters = self.env['ir.config_parameter'] model_names = config_parameters.get_param('mail_relocation_models') model_names = model_names.split(',') if model_names else [] if 'default_message_id' in self.env.context: message = self.env['mail.message'].browse( self.env.context['default_message_id']) if message.model and message.model not in model_names: model_names.append(message.model) if message.moved_from_model and message.moved_from_model not in model_names: model_names.append(message.moved_from_model) if model_names: selection = [(m.model, m.display_name) for m in self.env['ir.model'].search([('model', 'in', model_names)])] return selection @api.model def default_get(self, fields_list): res = super(wizard, self).default_get(fields_list) model_fields = self.fields_get() if model_fields['model']['selection']: res['model'] = model_fields['model']['selection'] and model_fields[ 'model']['selection'][0][0] if 'message_id' in res: message = self.env['mail.message'].browse(res['message_id']) email_from = message.email_from parts = email_split(email_from.replace(' ', ',')) if parts: email = parts[0] name = email_from[:email_from.index(email)].replace( '"', '').replace('<', '').strip() or email_from else: name, email = email_from res['message_name_from'] = name res['message_email_from'] = email res['partner_id'] = message.author_id.id if message.author_id and self.env.uid not in [ u.id for u in message.author_id.user_ids ]: res['filter_by_partner'] = True if message.author_id and res.get('model'): res_id = self.env[res['model']].search([], order='id desc', limit=1) res['res_id'] = res_id and res_id[0].id res['uid'] = self.env.uid return res message_id = fields.Many2one('mail.message', string='Message') message_body = fields.Html(related='message_id.body', string='Message to move', readonly=True) message_from = fields.Char(related='message_id.email_from', string='From', readonly=True) message_subject = fields.Char(related='message_id.subject', string='Subject', readonly=True) message_moved_by_message_id = fields.Many2one( 'mail.message', related='message_id.moved_by_message_id', string='Moved with', readonly=True) message_moved_by_user_id = fields.Many2one( 'res.users', related='message_id.moved_by_user_id', string='Moved by', readonly=True) message_is_moved = fields.Boolean(string='Is Moved', related='message_id.is_moved', readonly=True) parent_id = fields.Many2one( 'mail.message', string='Search by name', ) model = fields.Selection(_model_selection, string='Model') res_id = fields.Integer(string='Record') can_move = fields.Boolean('Can move', compute='get_can_move') move_back = fields.Boolean( 'MOVE TO ORIGIN', help='Move message and submessages to original place') partner_id = fields.Many2one('res.partner', string='Author') filter_by_partner = fields.Boolean('Filter Records by partner') message_email_from = fields.Char() message_name_from = fields.Char() # FIXME message_to_read should be True even if current message or any his childs are unread message_to_read = fields.Boolean(related='message_id.to_read') uid = fields.Integer() @api.depends('message_id') @api.one def get_can_move(self): # message was not moved before OR message is a top message of previous move self.can_move = not self.message_id.moved_by_message_id or self.message_id.moved_by_message_id.id == self.message_id.id @api.onchange('move_back') def on_change_move_back(self): if not self.move_back: return self.parent_id = self.message_id.moved_from_parent_id model = self.message_id.moved_from_model if self.message_id.is_moved: self.model = model self.res_id = self.message_id.moved_from_res_id @api.onchange('parent_id', 'res_id', 'model') def update_move_back(self): model = self.message_id.moved_from_model self.move_back = self.parent_id == self.message_id.moved_from_parent_id \ and self.res_id == self.message_id.moved_from_res_id \ and (self.model == model or (not self.model and not model)) @api.onchange('parent_id') def on_change_parent_id(self): if self.parent_id and self.parent_id.model: self.model = self.parent_id.model self.res_id = self.parent_id.res_id else: self.model = None self.res_id = None @api.onchange('model', 'filter_by_partner', 'partner_id') def on_change_partner(self): domain = {'res_id': []} if self.model and self.filter_by_partner and self.partner_id: fields = self.env[self.model].fields_get(False) contact_field = False for n, f in fields.iteritems(): if f['type'] == 'many2one' and f['relation'] == 'res.partner': contact_field = n break if contact_field: domain['res_id'] = [(contact_field, '=', self.partner_id.id)] if self.model: res_id = self.env[self.model].search(domain['res_id'], order='id desc', limit=1) self.res_id = res_id and res_id[0].id else: self.res_id = None return {'domain': domain} @api.one def check_access(self): cr = self._cr uid = self.env.user.id operation = 'write' context = self._context if not (self.model and self.res_id): return True model_obj = self.pool[self.model] mids = model_obj.exists(cr, uid, [self.res_id]) if hasattr(model_obj, 'check_mail_message_access'): model_obj.check_mail_message_access(cr, uid, mids, operation, context=context) else: self.pool['mail.thread'].check_mail_message_access( cr, uid, mids, operation, model_obj=model_obj, context=context) @api.multi def open_moved_by_message_id(self): message_id = None for r in self: message_id = r.message_moved_by_message_id.id return { 'type': 'ir.actions.act_window', 'res_model': 'mail_move_message.wizard', 'view_mode': 'form', 'view_type': 'form', 'views': [[False, 'form']], 'target': 'new', 'context': { 'default_message_id': message_id }, } @api.multi def move(self): for r in self: r.check_access() if not r.parent_id or not (r.parent_id.model == r.model and r.parent_id.res_id == r.res_id): #link with the first message of record parent = self.env['mail.message'].search( [('model', '=', r.model), ('res_id', '=', r.res_id)], order='id', limit=1) r.parent_id = parent.id or None r.message_id.move(r.parent_id.id, r.res_id, r.model, r.move_back) if not (r.model and r.res_id): obj = self.pool.get('ir.model.data').get_object_reference( self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1] return { 'type': 'ir.actions.client', 'name': 'Archive', 'tag': 'reload', 'params': { 'menu_id': obj }, } return { 'name': _('Record'), 'view_type': 'form', 'view_mode': 'form', 'res_model': r.model, 'res_id': r.res_id, 'views': [(False, 'form')], 'type': 'ir.actions.act_window', } @api.one def delete(self): self.message_id.unlink() return {} @api.model def create_partner(self, message_id, relation, partner_id, message_name_from, message_email_from): model = self.env[relation] message = self.env['mail.message'].browse(message_id) if not partner_id and message_name_from: partner_id = self.env['res.partner'].with_context({ 'update_message_author': True }).create({ 'name': message_name_from, 'email': message_email_from }).id context = {'partner_id': partner_id} if model._rec_name: context.update({'default_%s' % model._rec_name: message.subject}) fields = model.fields_get() contact_field = False for n, f in fields.iteritems(): if f['type'] == 'many2one' and f['relation'] == 'res.partner': contact_field = n break if contact_field: context.update({'default_%s' % contact_field: partner_id}) return context @api.one def read_close(self): self.message_id.set_message_read(True) self.message_id.child_ids.set_message_read(True) return {'type': 'ir.actions.act_window_close'}
class account_invoice_cashs(models.Model): _name = "account.invoice" _inherit = "account.invoice" # @api.one # @api.depends( # 'state', 'currency_id', 'invoice_line_ids.price_subtotal', # 'move_id.line_ids.amount_residual', # 'move_id.line_ids.currency_id') # def _compute_residual(self): # residual = 0.0 # residual_company_signed = 0.0 # sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 # for line in self.sudo().move_id.line_ids: # if line.account_id.internal_type in ('receivable', 'payable'): # residual_company_signed += line.amount_residual # if line.currency_id == self.currency_id: # residual += line.amount_residual_currency if line.currency_id else line.amount_residual # else: # from_currency = (line.currency_id and line.currency_id.with_context( # date=line.date)) or line.company_id.currency_id.with_context(date=line.date) # residual += from_currency.compute(line.amount_residual, self.currency_id) # self.residual_company_signed = abs(residual_company_signed) * sign # # #residual += self.cartage + self.labour # self.residual_signed = abs(residual) * sign # self.residual = abs(residual) # digits_rounding_precision = self.currency_id.rounding # if float_is_zero(self.residual, precision_rounding=digits_rounding_precision): # self.reconciled = True # else: # self.reconciled = False @api.model def create(self, vals): # vals = {} order_serch = self.env['account.invoice'] if vals.get('cash_credit') == 'cash_invoice': vals['serial_number'] = self.env['ir.sequence'].get( 'account.invoice.cashs') or '/' print "======vals['serial_number']=======", vals['serial_number'] elif vals.get('cash_credit') == 'credit_invoice': vals['serial_number'] = self.env['ir.sequence'].get( 'account.invoice.credits') or '/' print "======vals['serial_number']=======", vals['serial_number'] return super(account_invoice_cashs, self).create(vals) @api.multi def write(self, vals): if vals.get('cash_credit') == 'cash_invoice': vals['serial_number'] = self.env['ir.sequence'].get( 'account.invoice.cashs') or '/' print "======vals['serial_number']=======", vals['serial_number'] elif vals.get('cash_credit') == 'credit_invoice': vals['serial_number'] = self.env['ir.sequence'].get( 'account.invoice.credits') or '/' print "======vals['serial_number']=======", vals['serial_number'] return super(account_invoice_cashs, self).write(vals) def _compute_amount(self): self.amount_untaxed = sum(line.price_subtotal for line in self.invoice_line_ids) self.amount_tax = sum(line.amount for line in self.tax_line_ids) self.amount_total = self.amount_untaxed + self.amount_tax + self.cartage + self.labour amount_total_company_signed = self.amount_total amount_untaxed_signed = self.amount_untaxed if self.currency_id and self.currency_id != self.company_id.currency_id: amount_total_company_signed = self.currency_id.compute( self.amount_total, self.company_id.currency_id) amount_untaxed_signed = self.currency_id.compute( self.amount_untaxed, self.company_id.currency_id) sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 self.amount_total_company_signed = amount_total_company_signed * sign self.amount_total_signed = self.amount_total * sign self.amount_untaxed_signed = amount_untaxed_signed * sign cartage = fields.Float(string='Cartage', digits=dp.get_precision('Product Price')) labour = fields.Float(string='Labour', digits=dp.get_precision('Product Price')) cash_credit = fields.Selection([('cash_invoice', 'Cash'), ('credit_invoice', 'Credit')], string='Mode Of Payment', required=False, copy=False) serial_number = fields.Char(string='Serial Number', copy=False) debit_sequence = fields.Integer(string='Debit Sequence') penalty_date = fields.Date(string='Penalty Date') # reconciled = fields.Boolean(string='Paid/Reconciled', store=True, readonly=True, compute='_compute_residual') # residual = fields.Monetary(string='Amount Due', compute='_compute_residual', store=True) # residual_signed = fields.Monetary(string='Amount Due', currency_field='currency_id', compute='_compute_residual', # store=True) # residual_company_signed = fields.Monetary(string='Amount Due', currency_field='company_currency_id', # compute='_compute_residual', store=True) @api.multi def action_move_create(self): """ Creates invoice related analytics and financial move lines """ account_move = self.env['account.move'] for inv in self: if not inv.journal_id.sequence_id: raise UserError( _('Please define sequence on the journal related to this invoice.' )) if not inv.invoice_line_ids: raise UserError(_('Please create some invoice lines.')) if inv.move_id: continue ctx = dict(self._context, lang=inv.partner_id.lang) if not inv.date_invoice: inv.with_context(ctx).write( {'date_invoice': fields.Date.context_today(self)}) date_invoice = inv.date_invoice company_currency = inv.company_id.currency_id # create move lines (one per invoice line + eventual taxes and analytic lines) iml = inv.invoice_line_move_line_get() iml += inv.tax_line_move_line_get() diff_currency = inv.currency_id != company_currency # create one move line for the total and possibly adjust the other lines amount total, total_currency, iml = inv.with_context( ctx).compute_invoice_totals(company_currency, iml) # here creating an additional journal entry if cartage and Labour Exist if inv.cartage or inv.labour: iml.append({ 'type': 'src', 'name': 'Cartage And Labour', 'price': -(inv.cartage + inv.labour), 'price_unit': inv.cartage + inv.labour, 'account_id': self.env['account.account'].search( [('name', '=', 'Local Services')], limit=1).id, 'date_maturity': inv.date_due, 'amount_currency': diff_currency and company_currency.with_context(ctx).compute( inv.cartage + inv.labour, inv.currency_id), 'currency_id': diff_currency and inv.currency_id.id, 'invoice_id': inv.id, 'quantity': 1.0, }) name = inv.name or '/' if inv.payment_term_id: totlines = inv.with_context(ctx).payment_term_id.with_context( currency_id=inv.currency_id.id).compute( total, date_invoice)[0] res_amount_currency = total_currency ctx['date'] = date_invoice for i, t in enumerate(totlines): if inv.currency_id != company_currency: amount_currency = company_currency.with_context( ctx).compute(t[1] + inv.cartage + inv.labour, inv.currency_id) else: amount_currency = False # last line: add the diff res_amount_currency -= amount_currency or 0 if i + 1 == len(totlines): amount_currency += res_amount_currency iml.append({ 'type': 'dest', 'name': name, 'price': t[1] + company_currency.with_context(ctx).compute( inv.cartage + inv.labour, inv.currency_id), 'account_id': inv.account_id.id, 'date_maturity': t[0], 'amount_currency': diff_currency and amount_currency, 'currency_id': diff_currency and inv.currency_id.id, 'invoice_id': inv.id }) else: iml.append({ 'type': 'dest', 'name': name, 'price': total + inv.cartage + inv.labour, 'account_id': inv.account_id.id, 'date_maturity': inv.date_due, 'amount_currency': diff_currency and total_currency + company_currency.with_context(ctx).compute( inv.cartage + inv.labour, inv.currency_id), 'currency_id': diff_currency and inv.currency_id.id, 'invoice_id': inv.id }) print "IML....", iml part = self.env['res.partner']._find_accounting_partner( inv.partner_id) line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml] line = inv.group_lines(iml, line) journal = inv.journal_id.with_context(ctx) line = inv.finalize_invoice_move_lines(line) date = inv.date or date_invoice move_vals = { 'ref': inv.reference, 'line_ids': line, 'journal_id': journal.id, 'date': date, 'narration': inv.comment, } ctx['company_id'] = inv.company_id.id ctx['dont_create_taxes'] = True ctx['invoice'] = inv ctx_nolang = ctx.copy() ctx_nolang.pop('lang', None) move = account_move.with_context(ctx_nolang).create(move_vals) # Pass invoice in context in method post: used if you want to get the same # account move reference when creating the same invoice after a cancelled one: move.post() # make the invoice point to that move vals = { 'move_id': move.id, 'date': date, 'move_name': move.name, } inv.with_context(ctx).write(vals) return True @api.multi def invoice_print_custom(self): """ Print the invoice and mark it as sent, so that we can see more easily the next step of the workflow """ self.ensure_one() self.sent = True return self.env['report'].get_action( self, 'invoice_cartage.report_invoice_list')
class FleetVehicle(models.Model): _inherit = 'fleet.vehicle' @api.model def create(self, vals): acount_obj=self.env['account.analytic.account'] fleet_id = super(FleetVehicle, self).create(vals) account_id=acount_obj.create({'name':self._vehicle_name_get(fleet_id)}) fleet_id.write({'analytic_account_id':account_id.id,'use_tasks':True,'use_issues':True}) return fleet_id @api.multi def _count_vehicle_task(self): project_obj = self.env['project.project'] self.task_count=len(project_obj.search([('analytic_account_id', '=', self.analytic_account_id.id)]).task_ids) @api.multi def _count_vehicle_issue(self): issue_obj = self.env['project.project'] self.issue_count=len(issue_obj.search([('analytic_account_id', '=', self.analytic_account_id.id)]).issue_ids) @api.multi def write(self, vals): acount_obj=self.env['account.analytic.account'] res = super(FleetVehicle, self).write(vals) if not self.analytic_account_id: account_id=acount_obj.create({'name':self._vehicle_name_get(self)}) self.write({'analytic_account_id':account_id.id,'use_tasks':True,'use_issues':True}) self.analytic_account_id.write({'name':self.name,'use_tasks':True,'use_issues':True}) return res @api.multi def _vehicle_name_get(self,record): res = record.model_id.brand_id.name + '/' + record.model_id.name + '/' + record.license_plate return res @api.multi def action_view_alltasks(self): self.ensure_one() action = self.env.ref('project.act_project_project_2_project_task_all') domain=[('project_id.analytic_account_id', '=', self.analytic_account_id.id)] return { 'name': action.name, 'res_model': 'project.task', 'help': action.help, 'type': action.type, 'view_type': action.view_type, 'view_mode': action.view_mode, 'views': action.views, 'target': action.target, 'domain': domain, } @api.multi def action_view_allissues(self): self.ensure_one() action = self.env.ref('project_issue.act_project_project_2_project_issue_all') domain=[('project_id.analytic_account_id', '=', self.analytic_account_id.id)] return { 'name': action.name, 'res_model': 'project.issue', 'help': action.help, 'type': action.type, 'view_type': action.view_type, 'view_mode': action.view_mode, 'views': action.views, 'target': action.target, 'domain': domain, } analytic_account_id = fields.Many2one('account.analytic.account',string='Analytic Account') task_count = fields.Integer(compute=_count_vehicle_task, string="Vehicle Tasks" , multi=True) issue_count = fields.Integer(compute=_count_vehicle_issue, string="Vehicle Issues" , multi=True)
class CodaAccountMappingRule(models.Model): _name = 'coda.account.mapping.rule' _description = 'Rules Engine to assign accounts during CODA parsing' _order = 'sequence' coda_bank_account_id = fields.Many2one('coda.bank.account', string='CODA Bank Account', ondelete='cascade') sequence = fields.Integer( string='Sequence', default=10, help='Determines the order of the rules to assign accounts') name = fields.Char(string='Rule Name', required=True) active = fields.Boolean(string='Active', default=True, help='Switch on/off this rule.') # matching criteria trans_type_id = fields.Many2one('account.coda.trans.type', string='Transaction Type') trans_family_id = fields.Many2one('account.coda.trans.code', string='Transaction Family', domain=[('type', '=', 'family')]) trans_code_id = fields.Many2one('account.coda.trans.code', 'Transaction Code', domain=[('type', '=', 'code')]) trans_category_id = fields.Many2one('account.coda.trans.category', string='Transaction Category') partner_id = fields.Many2one( 'res.partner', string='Partner', ondelete='cascade', domain=['|', ('parent_id', '=', False), ('is_company', '=', True)]) freecomm = fields.Char(string='Free Communication', size=128) struct_comm_type_id = fields.Many2one( 'account.coda.comm.type', string='Structured Communication Type') structcomm = fields.Char(string='Structured Communication', size=128) payment_reference = fields.Char( string='Payment Reference', size=35, help="Payment Reference. For SEPA (SCT or SDD) transactions, " "the EndToEndReference is recorded in this field.") # results account_id = fields.Many2one('account.account', string='Account', ondelete='cascade', required=True, domain=[('type', '!=', 'view')]) tax_code_id = fields.Many2one('account.tax.code', string='Tax Case', ondelete='cascade') analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', ondelete='set null', domain=[('type', '!=', 'view'), ('state', 'not in', ('close', 'cancelled'))]) def _rule_select_extra(self, coda_bank_account_id): """ Use this method to customize the mapping rule engine. Cf. l10n_be_coda_analytic_plan module for an example. """ return '' def _rule_result_extra(self, coda_bank_account_id): """ Use this method to customize the mapping rule engine. Cf. l10n_be_coda_analytic_plan module for an example. """ return [] @api.model def rule_get(self, coda_bank_account_id, trans_type_id=None, trans_family_id=None, trans_code_id=None, trans_category_id=None, struct_comm_type_id=None, partner_id=None, freecomm=None, structcomm=None, payment_reference=None): select = \ 'SELECT trans_type_id, trans_family_id, trans_code_id, ' \ 'trans_category_id, ' \ 'struct_comm_type_id, partner_id, freecomm, structcomm, ' \ 'account_id, tax_code_id, analytic_account_id, payment_reference' select += self._rule_select_extra(coda_bank_account_id) + ' ' select += \ "FROM coda_account_mapping_rule " \ "WHERE active = TRUE AND coda_bank_account_id = %s " \ "ORDER BY sequence" % coda_bank_account_id self._cr.execute(select) rules = self._cr.dictfetchall() condition = \ "(not rule['trans_type_id'] or " \ "(trans_type_id == rule['trans_type_id'])) and " \ "(not rule['trans_family_id'] or " \ "(trans_family_id == rule['trans_family_id'])) " \ "and (not rule['trans_code_id'] or " \ "(trans_code_id == rule['trans_code_id'])) and " \ "(not rule['trans_category_id'] or " \ "(trans_category_id == rule['trans_category_id'])) " \ "and (not rule['struct_comm_type_id'] or " \ "(struct_comm_type_id == rule['struct_comm_type_id'])) and " \ "(not rule['partner_id'] or " \ "(partner_id == rule['partner_id'])) " \ "and (not rule['freecomm'] or (rule['freecomm'].lower() in " \ "(freecomm and freecomm.lower() or ''))) " \ "and (not rule['structcomm'] or " \ "(rule['structcomm'] in (structcomm or ''))) " \ "and (not rule['payment_reference'] or " \ "(rule['payment_reference'] in (payment_reference or ''))) " result_fields = ['account_id', 'tax_code_id', 'analytic_account_id'] result_fields += self._rule_result_extra(coda_bank_account_id) res = {} for rule in rules: if eval(condition): for f in result_fields: res[f] = rule[f] break return res
class budget_position(models.Model): """Budget Position""" _name = 'public_budget.budget_position' _description = 'Budget Position' _parent_order = 'code' _parent_store = True _order = "parent_left" code = fields.Char( string='Code', required=True ) name = fields.Char( string='Name', required=True ) type = fields.Selection( [(u'normal', u'Normal'), (u'view', u'View')], string='Type', required=True, default='normal' ) budget_assignment_allowed = fields.Boolean( string='Budget Assignment Allowed?' ) category_id = fields.Many2one( 'public_budget.budget_position_category', string='Category' ) inventariable = fields.Boolean( string='Inventariable?' ) draft_amount = fields.Float( string='Draft Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) preventive_amount = fields.Float( string='Preventive Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) definitive_amount = fields.Float( string='Definitive Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) to_pay_amount = fields.Float( string='To Pay Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) paid_amount = fields.Float( string='Paid Amount', compute='_get_amounts' ) balance_amount = fields.Float( string='Balance Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) projected_amount = fields.Float( string='Projected Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) projected_avg = fields.Float( string='Projected Avg', compute='_get_amounts', digits=dp.get_precision('Account'), ) preventive_avg = fields.Float( string='Preventive Perc.', compute='_get_amounts', digits=dp.get_precision('Account'), ) amount = fields.Float( string='Amount', compute='_get_amounts', digits=dp.get_precision('Account'), ) parent_left = fields.Integer( string='Parent Left', select=True ) parent_right = fields.Integer( string='Parent Right', select=True ) child_ids = fields.One2many( 'public_budget.budget_position', 'parent_id', string='Childs' ) parent_id = fields.Many2one( 'public_budget.budget_position', string='Parent', ondelete='cascade', context={'default_type': 'view'}, domain=[('type', '=', 'view')] ) budget_detail_ids = fields.One2many( 'public_budget.budget_detail', 'budget_position_id', string='budget_detail_ids' ) budget_modification_detail_ids = fields.One2many( 'public_budget.budget_modification_detail', 'budget_position_id', string='budget_modification_detail_ids' ) preventive_line_ids = fields.One2many( 'public_budget.preventive_line', 'budget_position_id', string='Preventive Lines' ) assignment_position_id = fields.Many2one( 'public_budget.budget_position', string='Assignment Position', compute='_get_assignment_position', store=True, ) @api.one # @api.depends( # 'preventive_line_ids.affects_budget', # 'preventive_line_ids.transaction_id.state', # 'preventive_line_ids.preventive_amount', # 'preventive_line_ids.definitive_line_ids.amount', # ) def _get_amounts(self): """Update the following fields with the related values to the budget and the budget position: -draft_amount: amount sum on preventive lines in draft state -preventive_amount: amount sum on preventive lines not in draft/cancel -definitive_amount: amount sum of definitive lines -to_pay_amount: amount sum of lines that has a related voucher in draft state -paid_amount: amount sum of lines that has a related voucher in open state -balance_amount: diffference between budget position and preventive amount """ if self.type == 'view': operator = 'child_of' if self.type == 'normal': operator = '=' domain = [ ('budget_position_id', operator, self.id), ('transaction_id.state', 'in', ('open', 'closed')), ('affects_budget', '=', True), ] budget_id = self._context.get('budget_id', False) # we add budget_assignment_allowed condition to optimize if budget_id and self.budget_assignment_allowed: domain.append(('budget_id', '=', budget_id)) modification_lines = self.env[ 'public_budget.budget_modification_detail'].search([ ('budget_modification_id.budget_id', '=', budget_id), ('budget_position_id', operator, self.id)]) modification_amounts = [line.amount for line in modification_lines] initial_lines = self.env['public_budget.budget_detail'].search([ ('budget_id', '=', budget_id), ('budget_position_id', operator, self.id)]) initial_amounts = [line.initial_amount for line in initial_lines] amount = sum(initial_amounts) + sum(modification_amounts) else: amount = False # we exclude lines from preventive lines because constraints sometimes # consider the line you are checking and sometimes not, so better we # exclude that line and compare to that line amount excluded_line_id = self._context.get('excluded_line_id', False) if excluded_line_id: domain.append(('id', '!=', excluded_line_id)) draft_preventive_lines = self.env[ 'public_budget.preventive_line'].search( domain ) active_preventive_lines = self.env[ 'public_budget.preventive_line'].search( domain ) preventive_amount = sum( [line.preventive_amount for line in active_preventive_lines]) self.draft_amount = sum([ line.preventive_amount for line in draft_preventive_lines]) self.preventive_amount = preventive_amount self.definitive_amount = sum( [line.definitive_amount for line in active_preventive_lines]) self.to_pay_amount = sum( [line.to_pay_amount for line in active_preventive_lines]) self.paid_amount = sum( [line.paid_amount for line in active_preventive_lines]) day_of_year = datetime.now().timetuple().tm_yday projected_amount = preventive_amount / day_of_year * 365 self.projected_amount = projected_amount if self.budget_assignment_allowed: projected_avg = amount and \ projected_amount / amount * 100.0 or 0.0 self.projected_avg = projected_avg self.amount = amount preventive_avg = amount and \ preventive_amount / amount * 100.0 or 0.0 self.preventive_avg = preventive_avg self.balance_amount = self.amount - preventive_amount @api.multi def name_get(self): result = [] for rec in self: result.append( (rec.id, "%s - %s" % (rec.code, rec.name))) return result @api.model def name_search(self, name, args=None, operator='ilike', limit=100): args = args or [] recs = self.browse() if name: recs = self.search([('code', operator, name)] + args, limit=limit) if not recs: recs = self.search([('name', operator, name)] + args, limit=limit) return recs.name_get() @api.one @api.constrains('child_ids', 'type', 'parent_id') def _check_type(self): if self.child_ids and self.type not in ('view'): raise Warning(_('You cannot define children to an account with \ internal type different of "View".')) @api.one @api.constrains( 'budget_modification_detail_ids', 'budget_detail_ids', 'child_ids', 'budget_assignment_allowed', 'parent_id' ) def _check_budget_assignment_allowed(self): # Check before seting budget_assignment_allowed false if position used if not self.budget_assignment_allowed and ( self.budget_modification_detail_ids or self.budget_detail_ids): raise Warning(_( "You can not set 'Budget Assignment Allowed' to false if\ budget position is being used in a budget detail or\ modification.")) if self.budget_assignment_allowed: # Check no parent has budget allowed if len(self.get_parent_assignment_position()) >= 1: raise Warning(_('In one branch only one budget position can\ have Budget Assignment Allowed.')) # Check no children has budget allowed else: children_allowed = self.search([ ('id', 'child_of', self.id), ('id', '!=', self.id), ('budget_assignment_allowed', '=', True)]) if children_allowed: raise Warning(_( 'You can not set position %s to Budget Posistion \ Allowed as the child position %s has Allowed.') % ( self.name, children_allowed[0].name)) @api.multi def get_parent_assignment_position(self): self.ensure_one() assignment_allowed = self.env['public_budget.budget_position'] parent = self.parent_id while parent: if parent.budget_assignment_allowed: assignment_allowed += parent parent = parent.parent_id return assignment_allowed @api.one @api.depends( 'parent_id', 'child_ids', 'budget_assignment_allowed', ) def _get_assignment_position(self): if self.budget_assignment_allowed: assignment_position = self else: assignment_position = self.get_parent_assignment_position() self.assignment_position_id = assignment_position.id
class eq_import_helper(models.Model): _name = 'eq_import_helper' ir_model = fields.Many2one('ir.model') old_id = fields.Integer('Old id') new_id = fields.Integer('New id')