class LunchAlert(models.Model): """ Alerts to display during a lunch order. An alert can be specific to a given day, weekly or daily. The alert is displayed from start to end hour. """ _name = 'lunch.alert' _description = 'Lunch Alert' display = fields.Boolean(compute='_compute_display_get') message = fields.Text('Message', required=True) alert_type = fields.Selection([('specific', 'Specific Day'), ('week', 'Every Week'), ('days', 'Every Day')], string='Recurrency', required=True, select=True, default='specific') specific_day = fields.Date('Day', default=fields.Date.context_today) monday = fields.Boolean('Monday') tuesday = fields.Boolean('Tuesday') wednesday = fields.Boolean('Wednesday') thursday = fields.Boolean('Thursday') friday = fields.Boolean('Friday') saturday = fields.Boolean('Saturday') sunday = fields.Boolean('Sunday') start_hour = fields.Float('Between', oldname='active_from', required=True, default=7) end_hour = fields.Float('And', oldname='active_to', required=True, default=23) active = fields.Boolean(default=True) @api.multi def name_get(self): return [(alert.id, '%s %s' % (_('Alert'), '#%d' % alert.id)) for alert in self] @api.one def _compute_display_get(self): """ This method check if the alert can be displayed today if alert type is specific : compare specific_day(date) with today's date if alert type is week : check today is set as alert (checkbox true) eg. self['monday'] if alert type is day : True return : Message if can_display_alert is True else False """ days_codes = {'0': 'sunday', '1': 'monday', '2': 'tuesday', '3': 'wednesday', '4': 'thursday', '5': 'friday', '6': 'saturday'} can_display_alert = { 'specific': (self.specific_day == fields.Date.context_today(self)), 'week': self[days_codes[datetime.datetime.now().strftime('%w')]], 'days': True } if can_display_alert[self.alert_type]: mynow = fields.Datetime.context_timestamp(self, datetime.datetime.now()) hour_to = int(self.end_hour) min_to = int((self.end_hour - hour_to) * 60) to_alert = datetime.time(hour_to, min_to) hour_from = int(self.start_hour) min_from = int((self.start_hour - hour_from) * 60) from_alert = datetime.time(hour_from, min_from) if from_alert <= mynow.time() <= to_alert: self.display = True else: self.display = False
class BrewOrder(models.Model): _name = "brew.order" @api.onchange("product_id") def onchange_product(self): if self.product_id: self.product_uom = self.product_id.uom_id @api.onchange("start_date") def onchange_start_date(self): if self.start_date: self.end_date = self.start_date self.wort_gathering_date = self.start_date @api.onchange("end_date") def onchange_end_date(self): if self.end_date: self.wort_gathering_date = self.end_date @api.one @api.depends("production_order_id") def _get_consumed_lines(self): for brew_order in self: raw_mat_moves = self.env["stock.move"] for child_mo in brew_order.production_order_id.child_mo_ids: raw_mat_moves |= child_mo.move_lines2.filtered( lambda record: record.state == "done") raw_mat_moves |= brew_order.production_order_id.move_lines2.filtered( lambda record: record.state == "done") brew_order.consumed_lines = raw_mat_moves @api.multi @api.depends("product_id", "brew_number", "brew_beer_number", "state", "start_date") def compute_display_name(self): year = date.today().year if self.start_date: year = datetime.strptime(self.start_date, DEFAULT_SERVER_DATETIME_FORMAT).year for order in self: if order.state in ["done", "cancel"]: order.name = u"%s_%s_%s" % ( order.product_id.code, year, order.brew_beer_number, ) elif order.state == "draft": order.name = u"%s_%s_%s" % ( order.product_id.code, year, order.state, ) @api.multi def get_bom(self): for brew_order in self: brew_order.bom = brew_order.production_order_id.bom_id name = fields.Char( string="Brew order", compute="compute_display_name", store=True, copy=False, ) brew_number = fields.Char(string="Brew number", copy=False) brew_beer_number = fields.Integer(string="Brew beer number", copy=False) state = fields.Selection( [("draft", "Draft"), ("done", "Done"), ("cancel", "Cancelled")], string="Status", readonly=True, default="draft", ) brew_declaration_id = fields.Many2one("brew.declaration", string="Brew declaration") start_date = fields.Datetime(string="Planned date", required=True) wort_gathering_date = fields.Datetime(string="Wort gathering date", required=True) end_date = fields.Datetime(string="End date", required=True) product_id = fields.Many2one( "product.product", string="Beer", domain=[("is_brewable", "=", True)], required=True, readonly=True, states={"draft": [("readonly", False)]}, ) product_qty = fields.Float( "Product Quantity", digits=dp.get_precision("Product Unit of Measure"), required=True, readonly=True, states={"draft": [("readonly", False)]}, ) product_uom = fields.Many2one( "product.uom", "Product Unit of Measure", required=True, readonly=True, states={"draft": [("readonly", False)]}, ) production_order_id = fields.Many2one("mrp.production", string="Production Order", readonly=True) consumed_lines = fields.One2many("stock.move", string="Consumed lines", compute=_get_consumed_lines) bom = fields.Many2one("mrp.bom", string="Bill of material", compute="get_bom") parent_brew_order_id = fields.Many2one("brew.order", string="parent brew order") child_brew_orders = fields.One2many("brew.order", "parent_brew_order_id", string="Child brew order") used_vessels_tank = fields.Char(string="Used vessels for work in tank") dry_extract = fields.Float(string="% dry extract") real_bulk_wort = fields.Float(string="Real bulk of wort") hl_plato_brewer = fields.Float(string="Hl plato noted by the brewer") hl_plato_agent = fields.Float(string="Hl plato noted by the agents") collecting_vessels = fields.Char(string="Collecting vessels") green_beer_volume = fields.Float(string="Volume of green Beer") sugar_quantity = fields.Float(string="Sugar") output_wort = fields.Float(string="Output wort") output_beer = fields.Float(string="Output beer") notes = fields.Char(string="Notes") @api.multi def action_confirm(self): bom_id = self.env["mrp.bom"]._bom_find(product_id=self.product_id.id, properties=[]) if self.parent_brew_order_id: if self.parent_brew_order_id.state != "done": raise UserError( _("You must first confirm the parent brew order.")) brew_sequence = parent_brew_order_id.brew_number else: brew_beer_number = ( self.product_id.brew_product_sequence.next_by_id()) brew_year_sequence = self.env["ir.sequence"].search([ ("code", "=", "brew.year.sequence") ]) brew_year_number = brew_year_sequence.next_by_id() self.write({ "state": "done", "brew_number": brew_year_number, "brew_beer_number": brew_beer_number, }) # create production order vals = { "product_id": self.product_id.id, "product_qty": self.product_qty, "product_uom": self.product_uom.id, "date_planned": self.start_date, "origin": self.name, "bom_id": bom_id, } prod_order_id = self.env["mrp.production"].create(vals) self.write({"production_order_id": prod_order_id.id}) @api.multi def action_cancel(self): return self.write({"state": "cancel"}) @api.multi def action_draft(self): return self.write({"state": "draft"})
class event_event(models.Model): """Event""" _name = 'event.event' _description = 'Event' _inherit = ['mail.thread', 'ir.needaction_mixin'] _order = 'date_begin' name = fields.Char(string='Name', translate=True, required=True, readonly=False, states={'done': [('readonly', True)]}) 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) type = fields.Many2one('event.type', string='Category', readonly=False, states={'done': [('readonly', True)]}) 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()) @api.model def _default_event_mail_ids(self): return [(0, 0, { 'interval_unit': 'now', 'interval_type': 'after_sub', 'template_id': self.env['ir.model.data'].xmlid_to_res_id( 'event.event_subscription') })] # Seats and computation seats_max = fields.Integer( string='Maximum Available Seats', oldname='register_max', readonly=True, states={'draft': [('readonly', False)]}, help= "You can for each event define a maximum registration level. If you have too much registrations you are not able to confirm your event. (put 0 to ignore this rule )" ) seats_availability = fields.Selection([('limited', 'Limited'), ('unlimited', 'Unlimited')], 'Available Seat', required=True, default='unlimited') seats_min = fields.Integer( string='Minimum Reserved Seats', oldname='register_min', readonly=True, states={'draft': [('readonly', False)]}, help= "You can for each event define a minimum registration level. If you do not enough registrations you are not able to confirm your event. (put 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='Available Seats', 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 Participations', store=True, 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) # 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', default=lambda self: self.env.user.tz) date_begin = fields.Datetime(string='Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}) date_end = fields.Datetime(string='End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}) 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='Auto Confirmation Activated', compute='_compute_auto_confirm') @api.one def _compute_auto_confirm(self): self.auto_confirm = self.env['ir.values'].get_default( 'marketing.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)]}) @api.multi @api.depends('name', 'date_begin', 'date_end') def name_get(self): result = [] for event in self: dates = [ dt.split(' ')[0] for dt in [event.date_begin, event.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_max and self.seats_available < 0: raise UserError(_('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 UserError( _('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('type') def _onchange_type(self): if self.type: self.seats_min = self.type.default_registration_min self.seats_max = self.type.default_registration_max self.reply_to = self.type.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 DonationDonation(models.Model): _name = 'donation.donation' _description = 'Donation' _order = 'id desc' _rec_name = 'display_name' _inherit = ['mail.thread'] @api.multi @api.depends('line_ids', 'line_ids.unit_price', 'line_ids.quantity', 'line_ids.product_id', 'donation_date', 'currency_id', 'company_id') def _compute_total(self): for donation in self: total = tax_receipt_total = 0.0 company_currency = donation.company_currency_id donation_currency = donation.currency_id # Do not consider other currencies for tax receipts # because, for the moment, only very very few countries # accept tax receipts from other countries, and never in another # currency. If you know such cases, please tell us and we will # update the code of this module for line in donation.line_ids: line_total = line.quantity * line.unit_price total += line_total if (donation_currency == company_currency and line.product_id.tax_receipt_ok): tax_receipt_total += line_total donation.amount_total = total donation_currency =\ donation.currency_id.with_context(date=donation.donation_date) total_company_currency = donation_currency.compute( total, donation.company_id.currency_id) donation.amount_total_company_currency = total_company_currency donation.tax_receipt_total = tax_receipt_total # We don't want a depends on partner_id.country_id, because if the partner # moves to another country, we want to keep the old country for # past donations to have good statistics @api.multi @api.depends('donation_by') def _compute_country_id(self): # Use sudo() to by-pass record rules, because the same partner # can have donations in several companies for donation in self: donation.sudo( ).country_id = donation.donation_by.partner_id.country_id @api.model def _default_currency(self): company = self.env['res.company']._company_default_get( 'donation.donation') return company.currency_id @api.model def _get_default_requested_by(self): return self.env['res.users'].browse(self.env.uid) currency_id = fields.Many2one('res.currency', string='Currency', required=True, states={3: [('readonly', True)]}, track_visibility='onchange', ondelete='restrict', default=_default_currency) partner_id = fields.Many2one('res.partner', string='Donor', index=True, states={3: [('readonly', True)]}, track_visibility='onchange', ondelete='restrict') commercial_partner_id = fields.Many2one( related='donation_by.partner_id.commercial_partner_id', string='Parent Donor', readonly=True, store=True, index=True) # country_id is here to have stats per country # WARNING : I can't put a related field, because when someone # writes on the country_id of a partner, it will trigger a write # on all it's donations, including donations in other companies # which will be blocked by the record rule country_id = fields.Many2one('res.country', string='Country', compute='_compute_country_id', store=True, readonly=True, copy=False) donation_by = fields.Many2one('res.users', 'Donation by', required=True, track_visibility='onchange', default=_get_default_requested_by) donation_place = fields.Many2one('donation.place', 'Donation Place', store=True) donation_section = fields.Many2one('donation.section', 'Section', store=True) gov_id = fields.Many2one('govs.villages.gov', related='donation_by.gov_id', string='Gov', store=True) check_total = fields.Monetary(string='Check Amount', digits=dp.get_precision('Account'), states={3: [('readonly', True)]}, currency_field='currency_id', track_visibility='onchange') amount_total = fields.Monetary(compute='_compute_total', string='Amount Total', currency_field='currency_id', store=True, digits=dp.get_precision('Account'), readonly=True) amount_total_company_currency = fields.Monetary( compute='_compute_total', string='Amount Total in Company Currency', currency_field='company_currency_id', store=True, digits=dp.get_precision('Account'), readonly=True) donation_date = fields.Date(string='Donation Date', required=True, default=fields.Date.context_today, states={3: [('readonly', True)]}, index=True, track_visibility='onchange') company_id = fields.Many2one('res.company', string='Company', required=True, states={3: [('readonly', True)]}, default=lambda self: self.env['res.company']. _company_default_get('donation.donation')) line_ids = fields.One2many('donation.line', 'donation_id', string='Donation Lines', states={3: [('readonly', True)]}, copy=True) move_id = fields.Many2one('account.move', string='Account Move', readonly=True, copy=False) move_analytic_id = fields.Many2many('account.analytic.line', string='Account Analytic', readonly=True) number = fields.Char(related='move_id.name', readonly=True, size=64, store=True, string='Donation Number') journal_id = fields.Many2one( 'account.journal', string='Payment Method', required=True, domain=[('type', 'in', ('bank', 'cash')), ('allow_donation', '=', True)], states={3: [('readonly', True)]}, track_visibility='onchange', default=lambda self: self.env.user.context_donation_journal_id) payment_ref = fields.Char(string='Payment Reference', size=32, states={3: [('readonly', True)]}) state = fields.Selection([ (1, 'Draft'), (2, 'Transfer'), (3, 'Done'), (4, 'Cancelled'), ], string='State', readonly=True, copy=False, default=1, index=True, track_visibility='onchange') company_currency_id = fields.Many2one(related='company_id.currency_id', string="Company Currency", readonly=True) campaign_id = fields.Many2one( 'donation.campaign', string='Donation Campaign', track_visibility='onchange', ondelete='restrict', default=lambda self: self.env.user.context_donation_campaign_id) display_name = fields.Char(string='Display Name', compute='_compute_display_name', readonly=True) #display_tag = fields.Char(string ='Tag') tax_receipt_id = fields.Many2one('donation.tax.receipt', string='Tax Receipt', readonly=True, copy=False) tax_receipt_option = fields.Selection([ ('none', 'None'), ('each', 'For Each Donation'), ('annual', 'Annual Tax Receipt'), ], string='Tax Receipt Option', states={3: [('readonly', True)]}, index=True) tax_receipt_total = fields.Monetary( compute='_compute_total', string='Eligible Tax Receipt Sub-total', store=True, currency_field='company_currency_id') tags_id = fields.Many2many('account.analytic.tag', string='Tags', readonly=True) donation_method = fields.Many2one('donation.instrument', store=True, string='Donation Method') account_id = fields.Many2one('account.account', related='donation_place.account_id', store=True, string='Account', readonly=True) product_id = fields.Many2one('product.product', domain=[('donation', '=', True)], string='Product', required=True, ondelete='restrict') #analytic = fields.Integer(string="id",compute='get_analytic_account_id_2') #analytic_tag = fields.Integer(string="tegid",compute='get_analytic_account_id_2') @api.multi @api.constrains('donation_date') def _check_donation_date(self): for donation in self: if donation.donation_date > fields.Date.context_today(self): # TODO No error pop-up to user : Odoo 9 BUG ? raise ValidationError( _('The date of the donation of %s should be today ' 'or in the past, not in the future!') % donation.donation_by.partner_id.name) @api.multi def _prepare_each_tax_receipt(self): self.ensure_one() vals = { 'company_id': self.company_id.id, 'currency_id': self.company_currency_id.id, 'donation_date': self.donation_date, 'amount': self.tax_receipt_total, 'type': 'each', 'partner_id': self.commercial_partner_id.id, } return vals @api.model def _prepare_move_line_name(self): name = _('Donation of %s') % self.donation_by.partner_id.name return name @api.multi def _prepare_counterpart_move_line(self, name, amount_total_company_cur, total_amount_currency, currency_id): self.ensure_one() precision = self.env['decimal.precision'].precision_get('Account') if float_compare(amount_total_company_cur, 0, precision_digits=precision) == 1: debit = amount_total_company_cur credit = 0 total_amount_currency = self.amount_total else: credit = amount_total_company_cur * -1 debit = 0 total_amount_currency = self.amount_total * -1 vals = { 'debit': debit, 'credit': credit, 'name': name, 'account_id': self.journal_id.default_debit_account_id.id, 'partner_id': self.commercial_partner_id.id, 'currency_id': currency_id, 'amount_currency': (currency_id and total_amount_currency or 0.0), } return vals @api.multi def _prepare_donation_move(self): self.ensure_one() if not self.journal_id.default_debit_account_id: raise UserError( _("Missing Default Debit Account on journal '%s'.") % self.journal_id.name) movelines = [] if self.company_id.currency_id.id != self.currency_id.id: currency_id = self.currency_id.id else: currency_id = False # Note : we can have negative donations for donors that use direct # debit when their direct debit rejected by the bank amount_total_company_cur = 0.0 total_amount_currency = 0.0 name = self._prepare_move_line_name() aml = {} # key = (account_id, analytic_account_id) # value = {'credit': ..., 'debit': ..., 'amount_currency': ...} precision = self.env['decimal.precision'].precision_get('Account') for donation_line in self.line_ids: if donation_line.in_kind: continue amount_total_company_cur += donation_line.amount_company_currency #account_id = donation_line.product_id.property_account_income_id.id #if not account_id: # account_id = donation_line.product_id.categ_id.\ # property_account_income_categ_id.id account_id = donation_line.get_account_id() if not account_id: raise UserError( _("Missing income account on product '%s' or on it's " "related product category") % donation_line.product_id.name) analytic_account_id = donation_line.get_analytic_account_id() amount_currency = 0.0 if float_compare(donation_line.amount_company_currency, 0, precision_digits=precision) == 1: credit = donation_line.amount_company_currency debit = 0 amount_currency = donation_line.amount * -1 else: debit = donation_line.amount_company_currency * -1 credit = 0 amount_currency = donation_line.amount # TODO Take into account the option group_invoice_lines ? if (account_id, analytic_account_id) in aml: aml[(account_id, analytic_account_id)]['credit'] += credit aml[(account_id, analytic_account_id)]['debit'] += debit aml[(account_id, analytic_account_id)]['amount_currency'] \ += amount_currency else: aml[(account_id, analytic_account_id)] = { 'credit': credit, 'debit': debit, 'amount_currency': amount_currency, } if not aml: # for full in-kind donation return False for (account_id, analytic_account_id), content in aml.iteritems(): movelines.append((0, 0, { 'name': name, 'credit': content['credit'], 'debit': content['debit'], 'account_id': account_id, 'analytic_account_id': analytic_account_id, 'partner_id': self.commercial_partner_id.id, 'currency_id': currency_id, 'amount_currency': (currency_id and content['amount_currency'] or 0.0), })) # counter-part ml_vals = self._prepare_counterpart_move_line( name, amount_total_company_cur, total_amount_currency, currency_id) movelines.append((0, 0, ml_vals)) vals = { 'journal_id': self.journal_id.id, 'date': self.donation_date, 'ref': self.payment_ref, 'line_ids': movelines, } return vals @api.one def _prepare_analytic_line(self): """ Prepare the values used to create() an account.analytic.line upon validation of an account.move.line having an analytic account. This method is intended to be extended in other modules. """ #for donation_line in self.line_ids: #if donation_line.in_kind: #continue #amount = (self.credit or 0.0) - (self.debit or 0.0) #account_id = self.line_ids.product_id.property_account_income_id.id for donation_line in self.line_ids: if donation_line.in_kind: continue account_id = donation_line.get_account_id() analytic_account_id = donation_line.get_analytic_account_id() #if not account_id: # account_id = self.line_ids.product_id.categ_id.property_account_income_categ_id.id name = self._prepare_move_line_name() vals = { 'name': name, 'date': self.donation_date, 'account_id': analytic_account_id, 'partner_id': self.commercial_partner_id.id, #'unit_amount': self.quantity, #'product_id': self.product_id and self.product_id.id or False, #'product_uom_id': self.product_uom_id and self.product_uom_id.id or False, 'unit_amount': False, 'product_id': False, 'product_uom_id': False, #'amount': self.company_currency_id.with_context(date=self.date or fields.Date.context_today(self)).compute(amount, self.analytic_account_id.currency_id) if self.analytic_account_id.currency_id else amount, 'amount': self.amount_total, 'general_account_id': account_id, 'ref': self.payment_ref, 'move_id': self.move_id.id, 'user_id': self._uid, 'tag_ids': self.tags_id, } return vals @api.multi def transfer(self): for rec in self: rec.state = 2 #self.env.cr.execute("SELECT place.tag_id FROM donation_donation inner join donation_place as place on donation_donation.donation_place = place.id where donation_donation.id= '%s'" %(self.id)) #res = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" %(rec.line_ids.id,res)) #self.env.cr.execute("SELECT gov.tag_id FROM donation_donation inner join govs_villages_gov as gov on donation_donation.gov_id = gov.id where donation_donation.id= '%s'" %(self.id)) #res2 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" %(rec.line_ids.id,res2)) #self.env.cr.execute("SELECT method.tag_id FROM donation_line inner join donation_instrument as method on donation_line.donation_method = method.id where donation_line.id= '%s'" %(self.line_ids.id)) #res3 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" %(rec.line_ids.id,res3)) self.env.cr.execute( "SELECT place.tag_id FROM donation_donation inner join donation_place as place on donation_donation.donation_place = place.id where donation_donation.id= '%s'" % (self.id)) res11 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_donation_rel(donation_donation_id, account_analytic_tag_id) VALUES ('%s','%s')" % (rec.id, res11)) self.env.cr.execute( "SELECT gov.tag_id FROM donation_donation inner join govs_villages_gov as gov on donation_donation.gov_id = gov.id where donation_donation.id= '%s'" % (self.id)) res12 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_donation_rel(donation_donation_id, account_analytic_tag_id) VALUES ('%s','%s')" % (rec.id, res12)) self.env.cr.execute( "SELECT method.tag_id FROM donation_donation inner join donation_instrument as method on donation_donation.donation_method = method.id where donation_donation.id= '%s'" % (self.id)) res13 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_donation_rel(donation_donation_id, account_analytic_tag_id) VALUES ('%s','%s')" % (rec.id, res13)) for donation_line in self.line_ids: self.env.cr.execute( "SELECT place.tag_id FROM donation_line inner join donation_place as place on donation_line.donation_place = place.id where donation_line.id= '%s'" % (donation_line.id)) res11 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" % (donation_line.id, res11)) self.env.cr.execute( "SELECT gov.tag_id FROM donation_line inner join govs_villages_gov as gov on donation_line.gov_id = gov.id where donation_line.id= '%s'" % (donation_line.id)) res12 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" % (donation_line.id, res12)) self.env.cr.execute( "SELECT method.tag_id FROM donation_line inner join donation_instrument as method on donation_line.donation_method = method.id where donation_line.id= '%s'" % (donation_line.id)) res13 = self.env.cr.fetchone()[0] rec.env.cr.execute( "insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" % (donation_line.id, res13)) @api.multi def validate(self): check_total = self.env['res.users'].has_group( 'donation.group_donation_check_total') precision = self.env['decimal.precision'].precision_get('Account') for donation in self: if not donation.line_ids: raise UserError( _("Cannot validate the donation of %s because it doesn't " "have any lines!") % donation.donation_by.partner_id.name) if float_is_zero(donation.amount_total, precision_digits=precision): raise UserError( _("Cannot validate the donation of %s because the " "total amount is 0 !") % donation.donation_by.partner_id.name) if donation.state != 2: raise UserError( _("Cannot validate the donation of %s because it is not " "in transfer state.") % donation.donation_by.partner_id.name) if check_total and donation.check_total != donation.amount_total: raise UserError( _("The amount of the donation of %s (%s) is different " "from the sum of the donation lines (%s).") % (donation.donation_by.partner_id.name, donation.check_total, donation.amount_total)) vals = {'state': 3} if donation.amount_total: move_vals = donation._prepare_donation_move() move_analytic_vals = donation._prepare_analytic_line()[0] # when we have a full in-kind donation: no account move if move_vals: move = self.env['account.move'].create(move_vals) #move.post() move_id2 = move.id vals['move_id'] = move.id for donation_line in self.line_ids: move_analytic = self.env[ 'account.analytic.line'].create(move_analytic_vals) move_analytic2 = move_analytic.id analytic = donation_line.analytic_account2.id account = donation_line.account_id.id #vals['move_analytic_id'] = move_analytic.id self.env.cr.execute( "insert INTO account_analytic_line_donation_donation_rel(donation_donation_id, account_analytic_line_id) VALUES ('%s','%s')" % (donation_line.donation_id.id, move_analytic.id)) self.env.cr.execute( "SELECT id FROM account_move_line where move_id = '%s' and account_id ='%d' and analytic_account_id ='%d' " % (move.id, account, analytic)) #and analytic_account_id ='%d' , analytic res111 = self.env.cr.fetchone()[0] self.env.cr.execute( "UPDATE account_analytic_line set move_id= '%s' where id= '%d'" % (res111, move_analytic.id)) #ress = (move.id*2) - 1 self.env.cr.execute( "UPDATE account_analytic_line set account_id= '%s' where id= '%d'" % (analytic, move_analytic.id)) self.env.cr.execute( "SELECT credit FROM account_move_line where move_id = '%s' and account_id ='%d' and id ='%d' " % (move.id, account, res111)) res111_amount = self.env.cr.fetchone()[0] self.env.cr.execute( "UPDATE account_analytic_line set amount= '%s' where id= '%d'" % (res111_amount, move_analytic.id)) resss = self.account_id.id self.env.cr.execute( "UPDATE account_analytic_line set general_account_id= '%s' where id= '%d'" % (resss, move_analytic.id)) ressss = self.commercial_partner_id.id self.env.cr.execute( "UPDATE account_analytic_line set partner_id= '%s' where id= '%d'" % (ressss, move_analytic.id)) ress2 = move_analytic.id self.env.cr.execute( "SELECT place.tag_id FROM donation_donation inner join donation_place as place on donation_donation.donation_place = place.id where donation_donation.id= '%s'" % (self.id)) res11 = self.env.cr.fetchone()[0] self.env.cr.execute( "insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" % (ress2, res11)) self.env.cr.execute( "SELECT gov.tag_id FROM donation_donation inner join govs_villages_gov as gov on donation_donation.gov_id = gov.id where donation_donation.id= '%s'" % (self.id)) res12 = self.env.cr.fetchone()[0] self.env.cr.execute( "insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" % (ress2, res12)) self.env.cr.execute( "SELECT method.tag_id FROM donation_donation inner join donation_instrument as method on donation_donation.donation_method = method.id where donation_donation.id= '%s'" % (self.id)) res13 = self.env.cr.fetchone()[0] self.env.cr.execute( "insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" % (ress2, res13)) else: donation.message_post( _('Full in-kind donation: no account move generated')) if (donation.tax_receipt_option == 'each' and donation.tax_receipt_total and not donation.tax_receipt_id): receipt_vals = donation._prepare_each_tax_receipt() receipt = self.env['donation.tax.receipt'].create(receipt_vals) vals['tax_receipt_id'] = receipt.id donation.write(vals) return @api.multi def save_default_values(self): self.ensure_one() self.env.user.write({ 'context_donation_journal_id': self.journal_id.id, 'context_donation_campaign_id': self.campaign_id.id, }) #@api.multi #def analytic(self): # for rec in self: # ress = (self.move_id.id *2) - 1 # self.env.cr.execute("UPDATE account_analytic_line set move_id= '%s' where id= '%d'" %(ress,self.move_analytic_id.id)) # ress2 = self.move_analytic_id.id # self.env.cr.execute("SELECT place.tag_id FROM donation_donation inner join donation_place as place on donation_donation.donation_place = place.id where donation_donation.id= '%s'" %(self.id)) # res11 = self.env.cr.fetchone()[0] # rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress2,res11)) # self.env.cr.execute("SELECT gov.tag_id FROM donation_donation inner join govs_villages_gov as gov on donation_donation.gov_id = gov.id where donation_donation.id= '%s'" %(self.id)) #res12 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress2,res12)) #self.env.cr.execute("SELECT method.tag_id FROM donation_donation inner join donation_instrument as method on donation_donation.donation_method = method.id where donation_donation.id= '%s'" %(self.id)) #res13 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress2,res13)) #self.env.cr.execute("SELECT place.tag_id FROM donation_donation inner join donation_place as place on donation_donation.donation_place = place.id where donation_donation.id= '%s'" %(self.id)) #res11 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress,res11)) #self.env.cr.execute("SELECT gov.tag_id FROM donation_donation inner join govs_villages_gov as gov on donation_donation.gov_id = gov.id where donation_donation.id= '%s'" %(self.id)) #res12 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress,res12)) #self.env.cr.execute("SELECT method.tag_id FROM donation_donation inner join donation_instrument as method on donation_donation.donation_method = method.id where donation_donation.id= '%s'" %(self.id)) #res13 = self.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_line_tag_rel(line_id, tag_id) VALUES ('%s','%s')" %(ress,res13)) @api.multi def done2cancel(self): '''from Done state to Cancel state''' for donation in self: if donation.tax_receipt_id: raise UserError( _("You cannot cancel this donation because " "it is linked to the tax receipt %s. You should first " "delete this tax receipt (but it may not be legally " "allowed).") % donation.tax_receipt_id.number) if donation.move_id: donation.move_id.button_cancel() donation.move_id.unlink() donation.state = 4 @api.multi def cancel2draft(self): '''from Cancel state to Draft state''' for donation in self: if donation.move_id: raise UserError( _("A cancelled donation should not be linked to " "an account move")) if donation.tax_receipt_id: raise UserError( _("A cancelled donation should not be linked to " "a tax receipt")) donation.state = 1 @api.multi def unlink(self): for donation in self: if donation.state == 3: raise UserError( _("The donation '%s' is in Done state, so you cannot " "delete it.") % donation.display_name) if donation.move_id: raise UserError( _("The donation '%s' is linked to an account move, " "so you cannot delete it.") % donation.display_name) if donation.tax_receipt_id: raise UserError( _("The donation '%s' is linked to the tax receipt %s, " "so you cannot delete it.") % (donation.display_name, donation.tax_receipt_id.number)) return super(DonationDonation, self).unlink() @api.multi @api.depends('state', 'donation_by', 'move_id') def _compute_display_name(self): for donation in self: if donation.state == 1: name = _('Draft Donation of %s' ) % donation.donation_by.partner_id.name elif donation.state == 4: name = _('Cancelled Donation of %s' ) % donation.donation_by.partner_id.name else: name = donation.number donation.display_name = name @api.onchange('donation_by') def partner_id_change(self): if self.donation_by.partner_id: self.tax_receipt_option = self.donation_by.partner_id.tax_receipt_option @api.onchange('tax_receipt_option') def tax_receipt_option_change(self): res = {} if (self.donation_by.partner_id and self.donation_by.partner_id.tax_receipt_option == 'annual' and self.tax_receipt_option != 'annual'): res = { 'warning': { 'title': _('Error:'), 'message': _('You cannot change the Tax Receipt ' 'Option when it is Annual.'), }, } self.tax_receipt_option = 'annual' return res
class ir_cron(models.Model): _inherit = 'ir.cron' interval_type = fields.Selection(selection_add=[('seconds', 'Seconds')])
class TaskOutput(models.Model): _name = "hc.task.output" _description = "Task Output" task_id = fields.Many2one(comodel_name="hc.res.task", string="Task", help="Task associated with this Task Output.") name = fields.Char(string="Name", required="True", help="Output Name.") value_type = fields.Selection(string="Value Type", selection=[ ("integer", "Integer"), ("decimal", "Decimal"), ("date_time", "Date Time"), ("date", "Date"), ("instant", "Instant"), ("string", "String"), ("uri", "URI"), ("boolean", "Boolean"), ("code", "Code"), ("markdown", "Markdown"), ("base_64_binary", "Base 64 Binary"), ("coding", "Coding"), ("codeable_concept", "Codeable Concept"), ("attachment", "Attachment"), ("identifier", "Identifier"), ("quantity", "Quantity"), ("range", "Range"), ("period", "Period"), ("ratio", "Ratio"), ("human_name", "Human Name"), ("address", "Address"), ("contact_point", "Contact Point"), ("timing", "Timing"), ("signature", "Signature"), ("reference", "Reference"), ("time", "Time"), ("oid", "OID"), ("id", "ID"), ("unsigned_int", "Unsigned Integer"), ("positive_int", "Positive Integer"), ("annotation", "Annotation"), ("sampled_data", "Sampled Data"), ("meta", "Meta") ], help="Type of specified output value.") value_name = fields.Char(string="Value", compute="_compute_value_name", store="True", help="Specified output value.") value_integer = fields.Integer(string="Value Integer", help="Integer output value.") value_decimal = fields.Float(string="Value Decimal", help="Decimal output value.") value_date_time = fields.Datetime(string="Value Date Time", help="Date Time output value.") value_date = fields.Date(string="Value Date", help="Date output value.") value_instant = fields.Datetime(string="Value Instant", help="Instant output value.") value_string = fields.Char(string="Value String", help="String output value.") value_uri = fields.Char(string="Value URI", help="URI output value.") value_boolean = fields.Boolean(string="Value Boolean", help="Boolean output value.") value_code_id = fields.Many2one(comodel_name="hc.vs.task.code", string="Value Code", help="Code output value.") value_markdown = fields.Text(string="Value Markdown", help="Markdown output value.") value_base_64_binary = fields.Binary(string="Value Base 64 Binary", help="Base 64 Binary output value.") value_coding_id = fields.Many2one(comodel_name="hc.vs.task.code", string="Value Coding", help="Coding output value.") value_codeable_concept_id = fields.Many2one( comodel_name="hc.vs.task.code", string="Value Codeable Concept", help="Codeable Concept output value.") value_attachment_id = fields.Many2one(comodel_name="hc.task.attachment", string="Value Attachment", help="Attachment output value.") value_identifier_id = fields.Many2one( comodel_name="hc.task.value.identifier", string="Value Identifier", help="Identifier output value.") value_quantity = fields.Float(string="Value Quantity", help="Quantity output value.") value_quantity_uom_id = fields.Many2one(comodel_name="product.uom", string="Value Quantity UOM", help="Quantity unit of measure.") value_range = fields.Char(string="Value Range", help="Range output value.") value_period = fields.Char(string="Value Period", help="Period output value.") value_period_uom_id = fields.Many2one(comodel_name="product.uom", string="Value Period UOM", help="Period unit of measure.") value_ratio = fields.Float(string="Value Ratio", help="Ratio of output value.") value_human_name_id = fields.Many2one(comodel_name="hc.task.human.name", string="Value Human Name", help="Human Name output value.") value_address_id = fields.Many2one(comodel_name="hc.task.address", string="Value Address", help="Address output value.") value_contact_point_id = fields.Many2one( comodel_name="hc.task.telecom", string="Value Contact Point", help="Contact Point output value.") value_timing_id = fields.Many2one(comodel_name="hc.task.timing", string="Value Timing", help="Timing output value.") value_signature_id = fields.Many2one(comodel_name="hc.task.signature", string="Value Signature", help="Signature output value.") value_reference_id = fields.Many2one(comodel_name="hc.task.reference", string="Value Reference", help="Reference output value.") value_time = fields.Float(string="Value Time", help="Time output value.") value_oid = fields.Char(string="Value OID", help="OID output value.") value_id = fields.Char(string="Value ID", help="ID output value.") value_unsigned_int = fields.Integer(string="Value Unsigned Integer", help="Unsigned Integer output value.") value_positive_int = fields.Integer(string="Value Positive Integer", help="Positive Integer output value.") value_annotation_id = fields.Many2one(comodel_name="hc.task.annotation", string="Value Annotation", help="Annotation output value.") value_sampled_data_id = fields.Many2one( comodel_name="hc.task.sampled.data", string="Value Sampled Data", help="Sampled Data output value.") value_meta_id = fields.Many2one(comodel_name="hc.task.meta", string="Value Meta", help="Meta output value.")
class ProjectTaskType(models.Model): _inherit = 'project.task.type' state = fields.Selection(_TASK_STATE, 'State')
class ComunicazioneLiquidazioneVp(models.Model): _name = 'comunicazione.liquidazione.vp' _description = 'Comunicazione Liquidazione IVA - Quadro VP' @api.multi @api.depends('iva_esigibile', 'iva_detratta') def _compute_VP6_iva_dovuta_credito(self): for quadro in self: quadro.iva_dovuta_debito = 0 quadro.iva_dovuta_credito = 0 if quadro.iva_esigibile >= quadro.iva_detratta: quadro.iva_dovuta_debito = quadro.iva_esigibile - \ quadro.iva_detratta else: quadro.iva_dovuta_credito = quadro.iva_detratta - \ quadro.iva_esigibile @api.multi @api.depends('iva_dovuta_debito', 'iva_dovuta_credito', 'debito_periodo_precedente', 'credito_periodo_precedente', 'credito_anno_precedente', 'versamento_auto_UE', 'crediti_imposta', 'interessi_dovuti', 'accounto_dovuto') def _compute_VP14_iva_da_versare_credito(self): """ Tot Iva a debito = (VP6, col.1 + VP7 + VP12) Tot Iva a credito = (VP6, col.2 + VP8 + VP9 + VP10 + VP11 + VP13) """ for quadro in self: quadro.iva_da_versare = 0 quadro.iva_a_credito = 0 if quadro.quarter == 5: continue debito = quadro.iva_dovuta_debito + quadro.debito_periodo_precedente\ + quadro.interessi_dovuti credito = quadro.iva_dovuta_credito \ + quadro.credito_periodo_precedente\ + quadro.credito_anno_precedente \ + quadro.versamento_auto_UE + quadro.crediti_imposta \ + quadro.accounto_dovuto if debito >= credito: quadro.iva_da_versare = debito - credito else: quadro.iva_a_credito = credito - debito comunicazione_id = fields.Many2one('comunicazione.liquidazione', string='Comunicazione', readonly=True) period_type = fields.Selection([('month', 'Monthly'), ('quarter', 'Quarterly')], string='Period type', default='month') month = fields.Integer(string='Month', default=False) quarter = fields.Integer(string='Quarter', default=False) subcontracting = fields.Boolean(string='Subcontracting') exceptional_events = fields.Selection([('1', 'Code 1'), ('9', 'Code 9')], string='Exceptional events') imponibile_operazioni_attive = fields.Float( string='Totale operazioni attive (al netto dell’IVA)') imponibile_operazioni_passive = fields.Float( string='Totale operazioni passive (al netto dell’IVA)') iva_esigibile = fields.Float(string='IVA esigibile') iva_detratta = fields.Float(string='IVA detratta') iva_dovuta_debito = fields.Float(string='IVA dovuta debito', compute="_compute_VP6_iva_dovuta_credito", store=True) iva_dovuta_credito = fields.Float( string='IVA dovuta credito', compute="_compute_VP6_iva_dovuta_credito", store=True) debito_periodo_precedente = fields.Float( string='Debito periodo precedente') credito_periodo_precedente = fields.Float( string='Credito periodo precedente') credito_anno_precedente = fields.Float(string='Credito anno precedente') versamento_auto_UE = fields.Float(string='Versamenti auto UE') crediti_imposta = fields.Float(string='Crediti d’imposta') interessi_dovuti = fields.Float( string='Interessi dovuti per liquidazioni trimestrali') accounto_dovuto = fields.Float(string='Acconto dovuto') iva_da_versare = fields.Float( string='IVA da versare', compute="_compute_VP14_iva_da_versare_credito", store=True) iva_a_credito = fields.Float( string='IVA a credito', compute="_compute_VP14_iva_da_versare_credito", store=True)
class is_cout_calcul(models.Model): _name='is.cout.calcul' _order='name desc' name = fields.Datetime('Date', required=True , readonly=True) user_id = fields.Many2one('res.users', 'Responsable', readonly=True) product_id = fields.Many2one('product.product', 'Article') segment_id = fields.Many2one('is.product.segment', 'Segment') is_category_id = fields.Many2one('is.category', 'Catégorie') is_gestionnaire_id = fields.Many2one('is.gestionnaire', 'Gestionnaire') multiniveaux = fields.Boolean('Calcul des coûts multi-niveaux') cout_actualise_ids = fields.One2many('is.cout.calcul.actualise', 'cout_calcul_id', u"Historique des côuts actualisés") niveau_ids = fields.One2many('is.cout.calcul.niveau' , 'cout_calcul_id', u"Niveau des articles dans la nomenclature") log_ids = fields.One2many('is.cout.calcul.log', 'cout_calcul_id', u"Logs") state = fields.Selection([('creation',u'Création'), ('prix_achat', u"Calcul des prix d'achat"),('termine', u"Terminé")], u"État", readonly=True, select=True) _defaults = { 'name': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id': lambda self, cr, uid, c: uid, 'multiniveaux': True, 'state': 'creation', } detail_nomenclature=[] detail_gamme_ma=[] detail_gamme_mo=[] detail_gamme_ma_pk=[] detail_gamme_mo_pk=[] mem_couts={} @api.multi @api.multi def nomenclature(self, cout_calcul_obj, product, niveau, multiniveaux=True): cr = self._cr type_article=self.type_article(product) cout=self.creation_cout(cout_calcul_obj, product, type_article) if type_article!='A' and multiniveaux==True: if niveau>10: raise Warning(u"Trop de niveaux (>10) dans la nomenclature du "+product.is_code) SQL=""" select mbl.product_id, mbl.id, mbl.sequence, mb.id from mrp_bom mb inner join mrp_bom_line mbl on mbl.bom_id=mb.id inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id where pp.id="""+str(product.id)+ """ order by mbl.sequence, mbl.id """ #TODO : Voir si ce filtre est necessaire : and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null) cr.execute(SQL) result = cr.fetchall() niv=niveau+1 for row2 in result: composant=self.env['product.product'].browse(row2[0]) self.nomenclature(cout_calcul_obj, composant, niv) @api.multi def type_article(self, product): type_article="" for route in product.route_ids: if type_article=='F' and route.name=='Buy': type_article='ST' if type_article=='A' and route.name=='Manufacture': type_article='ST' if type_article=='' and route.name=='Manufacture': type_article='F' if type_article=='' and route.name=='Buy': type_article='A' return type_article @api.multi def creation_cout(self, cout_calcul_obj, product, type_article, niveau=0): product_id=product.id #_logger.info('creation_cout : len(mem_couts)='+str(len(self.mem_couts))) if product_id in self.mem_couts: action='trouvé' cout=self.mem_couts[product_id] else: cout_obj = self.env['is.cout'] couts=cout_obj.search([('name', '=', product_id)]) vals={ 'cout_calcul_id': cout_calcul_obj.id, 'type_article' : type_article, 'niveau' : niveau, } if len(couts): action='write' cout=couts[0] cout.write(vals) else: action='create' vals['name'] = product_id cout=cout_obj.create(vals) self.mem_couts[product_id]=cout return cout @api.multi def action_imprimer_couts(self): for obj in self: tmp=tempfile.mkdtemp() os.system('mkdir '+tmp) ct=1 nb=len(obj.cout_actualise_ids) for line in obj.cout_actualise_ids: couts=self.env['is.cout'].search([('name', '=', line.product_id.id)]) for cout in couts: path=tmp+"/"+str(ct)+".pdf" ct=ct+1 pdf = self.env['report'].get_pdf(cout, 'is_plastigray.report_is_cout') f = open(path,'wb') f.write(pdf) f.close() os.system('pdfjoin -o '+tmp+'/merged.pdf '+tmp+'/*.pdf') pdf = open(tmp+'/merged.pdf','rb').read() os.system('rm '+tmp+'/*.pdf') os.system('rmdir '+tmp) # ** Recherche si une pièce jointe est déja associèe *************** model=self._name name='Couts.pdf' attachment_obj = self.env['ir.attachment'] attachments = attachment_obj.search([('res_model','=',model),('res_id','=',obj.id),('name','=',name)]) # ****************************************************************** # ** Creation ou modification de la pièce jointe ******************* vals = { 'name': name, 'datas_fname': name, 'type': 'binary', 'res_model': model, 'res_id': obj.id, 'datas': pdf.encode('base64'), } attachment_id=False if attachments: for attachment in attachments: attachment.write(vals) attachment_id=attachment.id else: attachment = attachment_obj.create(vals) attachment_id=attachment.id return { 'type' : 'ir.actions.act_url', 'url': '/web/binary/saveas?model=ir.attachment&field=datas&id='+str(attachment_id)+'&filename_field=name', 'target': 'self', } #******************************************************************* @api.multi def _log(self,operation): _logger.info(operation) for obj in self: vals={ 'cout_calcul_id': obj.id, 'date' : datetime.datetime.now(), 'operation' : operation, } res=self.env['is.cout.calcul.log'].create(vals) # @api.multi # def action_calcul_prix_achat(self): # cr = self._cr # debut=datetime.datetime.now() # for obj in self: # #obj.log_ids.unlink() # self._log("## DEBUT Calcul des prix d'achat") # _logger.info('début unlink') # for row in obj.cout_actualise_ids: # row.unlink() # _logger.info('fin unlink') # calcul_actualise_obj = self.env['is.cout.calcul.actualise'] # _logger.info("début get_products") # products=self.get_products(obj) # _logger.info("fin get_products : nb="+str(len(products))) # #TODO : 0.07s par article (88s pour 1233 articles) # ct=1 # nb=len(products) # #print _now(debut), "## début boucle products : nb=",nb # _logger.info("début boucle products : nb="+str(nb)) # for product in products: # _logger.info(str(ct)+'/'+str(nb)+' : boucle products : '+product.is_code) # #print _now(debut), product,ct,'/',nb # ct+=1 # self.nomenclature(obj,product,0, obj.multiniveaux) # couts=self.env['is.cout'].search([('cout_calcul_id', '=', obj.id)]) # product_uom_obj = self.env['product.uom'] # #print _now(debut), "## fin boucle products" # _logger.info("fin boucle products") # ct=1 # nb=len(couts) # #print _now(debut), "## début boucle couts : nb=",nb # _logger.info("début boucle couts : nb="+str(nb)) # for cout in couts: # product=cout.name # _logger.info(str(ct)+'/'+str(nb)+' : boucle couts : '+product.is_code) # #print _now(debut), product.is_code,ct,'/',nb # ct+=1 # prix_tarif = 0 # prix_commande = 0 # prix_facture = 0 # prix_calcule = 0 # ecart_calcule_matiere = 0 # vals={ # 'cout_calcul_id': obj.id, # 'product_id': product.id, # } # res=calcul_actualise_obj.create(vals) # type_article=cout.type_article # if type_article!='F': # #** Recherche du fournisseur par défaut ******************** # seller=False # if len(product.seller_ids)>0: # seller=product.seller_ids[0] # pricelist=False # if seller: # partner=seller.name # pricelist=partner.property_product_pricelist_purchase # #*********************************************************** # #** Recherche du prix d'achat ****************************** # date=time.strftime('%Y-%m-%d') # Date du jour # if pricelist: # #Convertion du lot_mini de US vers UA # min_quantity = product_uom_obj._compute_qty(cout.name.uom_id.id, cout.name.lot_mini, cout.name.uom_po_id.id) # #TODO : Pour contourner un bug d'arrondi (le 31/01/2017) # min_quantity=min_quantity+0.00000000001 # #TODO en utilisant la fonction repr à la place de str, cela ne tronque pas les décimales # SQL=""" # select ppi.price_surcharge # from product_pricelist_version ppv inner join product_pricelist_item ppi on ppv.id=ppi.price_version_id # where ppv.pricelist_id="""+str(pricelist.id)+ """ # and min_quantity<="""+repr(min_quantity)+""" # and (ppv.date_start <= '"""+date+"""' or ppv.date_start is null) # and (ppv.date_end >= '"""+date+"""' or ppv.date_end is null) # and ppi.product_id="""+str(product.id)+ """ # and (ppi.date_start <= '"""+date+"""' or ppi.date_start is null) # and (ppi.date_end >= '"""+date+"""' or ppi.date_end is null) # order by ppi.sequence # limit 1 # """ # cr.execute(SQL) # result = cr.fetchall() # for row in result: # #coef=product.uom_po_id.factor_inv # coef=1 # if min_quantity: # coef=cout.name.lot_mini/min_quantity # prix_tarif=row[0]/coef # #*********************************************************** # #** Recherche prix dernière commande *********************** # SQL=""" # select pol.price_unit*pu.factor # from purchase_order_line pol inner join product_uom pu on pol.product_uom=pu.id # where pol.product_id="""+str(product.id)+ """ # and state in('confirmed','done') # order by pol.id desc limit 1 # """ # cr.execute(SQL) # result = cr.fetchall() # for row in result: # prix_commande=row[0] # #*********************************************************** # #** Recherche prix dernière facture ************************ # SQL=""" # select ail.price_unit*pu.factor # from account_invoice_line ail inner join product_uom pu on ail.uos_id=pu.id # inner join account_invoice ai on ail.invoice_id=ai.id # where ail.product_id="""+str(product.id)+ """ # and ai.state in('open','paid') and ai.type='in_invoice' # order by ail.id desc limit 1 # """ # cr.execute(SQL) # result = cr.fetchall() # for row in result: # prix_facture=row[0] # #*********************************************************** # if cout.prix_force: # prix_calcule=cout.prix_force # else: # if prix_facture: # prix_calcule=prix_facture # else: # if prix_commande: # prix_calcule=prix_commande # else: # if prix_tarif: # prix_calcule=prix_tarif # if type_article=='A': # if prix_calcule==0: # prix_calcule=cout.cout_act_matiere # ecart_calcule_matiere = prix_calcule - cout.cout_act_matiere # if type_article=='ST': # if prix_calcule==0: # prix_calcule=cout.cout_act_st # ecart_calcule_matiere = prix_calcule - cout.cout_act_st # if prix_tarif: # cout.prix_tarif=prix_tarif # cout.type_article = type_article # cout.prix_commande = prix_commande # cout.prix_facture = prix_facture # cout.prix_calcule = prix_calcule # cout.ecart_calcule_matiere = ecart_calcule_matiere # obj.state="prix_achat" # self._log("## FIN Calcul des prix d'achat"+_now(debut)) @api.multi def get_products(self,obj): cats=self.env['is.category']._calcul_cout() products={} if obj.product_id: products=self.env['product.product'].search([('id', '=', obj.product_id.id), ('is_category_id', 'in', cats)]) else: if obj.segment_id: products=self.env['product.product'].search([('segment_id', '=', obj.segment_id.id), ('is_category_id', 'in', cats)], limit=10000) else: if obj.is_category_id: products=self.env['product.product'].search([('is_category_id', '=', obj.is_category_id.id)], limit=10000) else: if obj.is_gestionnaire_id: products=self.env['product.product'].search([('is_gestionnaire_id', '=', obj.is_gestionnaire_id.id), ('is_category_id', 'in', cats)], limit=10000) else: products=self.env['product.product'].search([('is_category_id', 'in', cats)]) return products @api.multi def nomenclature_prix_revient(self, cout_calcul_obj, niveau, product, unite=False, quantite_unitaire=1, quantite_total=1, prix_calcule=0): cr = self._cr type_article=self.type_article(product) cout_mat = 0 cout_st = 0 msg_err='' if product.is_category_id.name!='80': if type_article=='A': cout_mat = prix_calcule if prix_calcule==0: msg_err=u'Err Coût Mat' if type_article=='ST': cout_st = prix_calcule if prix_calcule==0: msg_err=u'Err Coût ST' cout=self.creation_cout(cout_calcul_obj, product, type_article) self.detail_nomenclature.append({ 'product_id' : product.id, 'is_code' : product.is_code, 'composant' : '----------'[:niveau]+str(product.is_code), 'designation' : product.name, 'unite' : unite, 'quantite' : quantite_unitaire, 'cout_mat' : cout_mat, 'total_mat' : quantite_total*cout_mat, 'cout_st' : cout_st, 'total_st' : quantite_total*cout_st, 'msg_err' : msg_err, }) if type_article!='A': lot_mini=product.lot_mini if lot_mini==0: lot_mini=1 #** Recherche de la gamme ****************************************** SQL=""" select mb.routing_id from mrp_bom mb inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id where pp.id="""+str(product.id)+ """ and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null) order by mb.id """ cr.execute(SQL) result = cr.fetchall() for row2 in result: routing_id = row2[0] if routing_id: routing = self.env['mrp.routing'].browse(routing_id) for line in routing.workcenter_lines: cout_total=quantite_unitaire*line.workcenter_id.costs_hour*round(line.is_nb_secondes/3600,4) vals={ 'composant' : '----------'[:niveau]+product.is_code, 'sequence' : line.sequence, 'workcenter_id' : line.workcenter_id.id, 'quantite' : quantite_unitaire, 'cout_prepa' : line.workcenter_id.costs_hour, 'tps_prepa' : line.workcenter_id.time_start, 'cout_fab' : line.workcenter_id.costs_hour, 'tps_fab' : line.is_nb_secondes, 'cout_total' : cout_total, } if line.workcenter_id.resource_type=='material': self.detail_gamme_ma.append(vals) else: self.detail_gamme_mo.append(vals) #** Recherche de la gamme générique pour Cout Plasti-ka ************ SQL=""" select mb.is_gamme_generique_id from mrp_bom mb inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id where pp.id="""+str(product.id)+ """ order by mb.id """ cr.execute(SQL) result = cr.fetchall() for row2 in result: routing_id = row2[0] if routing_id: routing = self.env['mrp.routing'].browse(routing_id) for line in routing.workcenter_lines: cout_total=quantite_unitaire*line.workcenter_id.is_cout_pk*round(line.is_nb_secondes/3600,4) vals={ 'composant' : '----------'[:niveau]+product.is_code, 'sequence' : line.sequence, 'workcenter_id' : line.workcenter_id.id, 'quantite' : quantite_unitaire, 'cout_prepa' : line.workcenter_id.is_cout_pk, 'tps_prepa' : line.workcenter_id.time_start, 'cout_fab' : line.workcenter_id.is_cout_pk, 'tps_fab' : line.is_nb_secondes, 'cout_total' : cout_total, } if line.workcenter_id.resource_type=='material': self.detail_gamme_ma_pk.append(vals) else: self.detail_gamme_mo_pk.append(vals) #******************************************************************* #** Composants de la nomenclature ********************************** SQL=""" select mbl.product_id, mbl.product_uom, mbl.product_qty, ic.prix_calcule from mrp_bom mb inner join mrp_bom_line mbl on mbl.bom_id=mb.id inner join product_product pp on pp.product_tmpl_id=mb.product_tmpl_id inner join is_cout ic on ic.name=mbl.product_id where pp.id="""+str(product.id)+ """ order by mbl.sequence, mbl.id """ # TODO : Filtre sur ce critère ? => and (mb.is_sous_traitance='f' or mb.is_sous_traitance is null) cr.execute(SQL) result = cr.fetchall() niv=niveau+1 for row2 in result: composant = self.env['product.product'].browse(row2[0]) unite = row2[1] qt_unitaire = row2[2] qt_total = qt_unitaire*quantite_total prix_calcule = row2[3] self.nomenclature_prix_revient(cout_calcul_obj, niv, composant, unite, qt_unitaire, qt_total, prix_calcule) #******************************************************************* @api.multi def _productid2cout(self,product_id): cout_obj = self.env['is.cout'] couts=cout_obj.search([('name', '=', product_id)]) return couts @api.multi def _get_couts(self): couts=[] for obj in self: for row in obj.cout_actualise_ids: product=row.product_id res=self._productid2cout(product.id) for r in res: couts.append(r) return couts @api.multi def _unlink_detail_cout(self,couts): """En regroupant la suppression de toutes les lignes, cela permet de gagner beaucoup de temps""" cr = self._cr if couts: ids = self._get_couts_ids(couts) if ids: ids=','.join(ids) SQL='' SQL+='DELETE FROM is_cout_nomenclature WHERE cout_id in('+ids+'); ' SQL+='DELETE FROM is_cout_gamme_ma WHERE cout_id in('+ids+'); ' SQL+='DELETE FROM is_cout_gamme_mo WHERE cout_id in('+ids+'); ' SQL+='DELETE FROM is_cout_gamme_ma_pk WHERE cout_id in('+ids+'); ' SQL+='DELETE FROM is_cout_gamme_mo_pk WHERE cout_id in('+ids+'); ' cr.execute(SQL) @api.multi def _get_couts_ids(self,couts): """Retourne la liste des id des couts à partir des couts""" ids=[] for cout in couts: ids.append(str(cout.id)) return ids @api.multi def _write_resultats(self): "Ecrit les résultats des calculs dans la page récapitulative" for obj in self: for row in obj.cout_actualise_ids: product=row.product_id couts=self._productid2cout(product.id) for cout in couts: vals={} vals['cout_act_matiere'] = cout.cout_act_matiere vals['cout_act_machine'] = cout.cout_act_machine vals['cout_act_mo'] = cout.cout_act_mo vals['cout_act_st'] = cout.cout_act_st vals['cout_act_total'] = cout.cout_act_total row.write(vals) @api.multi def action_calcul_prix_revient(self): #pr=cProfile.Profile() #pr.enable() for obj in self: self._log("## DEBUT Calcul des prix de revient") nb=len(obj.cout_actualise_ids) ct=0 couts = self._get_couts() self._unlink_detail_cout(couts) for cout in couts: product=cout.name ct=ct+1 _logger.info(str(ct)+'/'+str(nb)+' : '+str(product.is_code)) cout_act_matiere = 0 cout_act_st = 0 cout_act_condition = 0 cout_act_machine = 0 cout_act_machine_pk = 0 cout_act_mo = 0 cout_act_mo_pk = 0 cout_act_total = 0 if cout.type_article=='A': cout_act_matiere = cout.prix_calcule cout_act_st = 0 if cout.type_article=='ST': cout_act_matiere = 0 cout_act_st = 0 nb_err=0 if cout.type_article!='A': self.detail_nomenclature=[] self.detail_gamme_ma=[] self.detail_gamme_mo=[] self.detail_gamme_ma_pk=[] self.detail_gamme_mo_pk=[] self.nomenclature_prix_revient(obj, 0, product, False, 1, 1, cout.prix_calcule) for vals in self.detail_nomenclature: if vals['msg_err']!='': nb_err=nb_err+1 is_code=vals['is_code'] if is_code[:1]=="7": cout_act_condition=cout_act_condition+vals['total_mat'] del vals['is_code'] vals['cout_id']=cout.id cout_act_matiere = cout_act_matiere+vals['total_mat'] cout_act_st = cout_act_st+vals['total_st'] res=self.env['is.cout.nomenclature'].create(vals) vals={ 'cout_id' : cout.id, 'designation' : 'TOTAL : ', 'total_mat' : cout_act_matiere, 'total_st' : cout_act_st, } res=self.env['is.cout.nomenclature'].create(vals) vals={ 'cout_id' : cout.id, 'designation' : 'Conditionnement : ', 'total_mat' : cout_act_condition, } res=self.env['is.cout.nomenclature'].create(vals) for vals in self.detail_gamme_ma: vals['cout_id']=cout.id res=self.env['is.cout.gamme.ma'].create(vals) cout_act_machine = cout_act_machine+vals['cout_total'] for vals in self.detail_gamme_mo: vals['cout_id']=cout.id res=self.env['is.cout.gamme.mo'].create(vals) cout_act_mo = cout_act_mo+vals['cout_total'] for vals in self.detail_gamme_ma_pk: vals['cout_id']=cout.id res=self.env['is.cout.gamme.ma.pk'].create(vals) cout_act_machine_pk = cout_act_machine_pk+vals['cout_total'] for vals in self.detail_gamme_mo_pk: vals['cout_id']=cout.id res=self.env['is.cout.gamme.mo.pk'].create(vals) cout_act_mo_pk = cout_act_mo_pk+vals['cout_total'] vals={} #Client par défaut for row in product.is_client_ids: if row.client_defaut: vals['partner_id']=row.client_id.id vals['nb_err'] = nb_err if nb_err>0: cout_act_matiere=0 cout_act_total=cout_act_matiere+cout_act_machine+cout_act_mo+cout_act_st vals['cout_act_matiere'] = cout_act_matiere vals['cout_act_condition'] = cout_act_condition vals['cout_act_machine'] = cout_act_machine vals['cout_act_mo'] = cout_act_mo vals['cout_act_machine_pk'] = cout_act_machine_pk vals['cout_act_mo_pk'] = cout_act_mo_pk vals['cout_act_st'] = cout_act_st vals['cout_act_total'] = cout_act_total vals['is_category_id'] = product.is_category_id.id vals['is_gestionnaire_id'] = product.is_gestionnaire_id.id vals['is_mold_id'] = product.is_mold_id.id vals['is_mold_dossierf'] = product.is_mold_dossierf vals['uom_id'] = product.uom_id.id vals['lot_mini'] = product.lot_mini vals['cout_act_prix_vente'] = cout.prix_vente-cout.amortissement_moule-cout.surcout_pre_serie cout.write(vals) self._write_resultats() obj.state="termine" self._log("## FIN Calcul des prix de revient")
class AccountFrFec(models.TransientModel): _name = 'account.fr.fec' _description = 'Ficher Echange Informatise' date_from = fields.Date(string='Start Date', required=True) date_to = fields.Date(string='End Date', required=True) fec_data = fields.Binary('FEC File', readonly=True) filename = fields.Char(string='Filename', size=256, readonly=True) export_type = fields.Selection([ ('official', 'Official FEC report (posted entries only)'), ('nonofficial', 'Non-official FEC report (posted and unposted entries)'), ], string='Export Type', required=True, default='official') @api.multi def generate_fec(self): self.ensure_one() # We choose to implement the flat file instead of the XML # file for 2 reasons : # 1) the XSD file impose to have the label on the account.move # but Odoo has the label on the account.move.line, so that's a # problem ! # 2) CSV files are easier to read/use for a regular accountant. # So it will be easier for the accountant to check the file before # sending it to the fiscal administration header = [ 'JournalCode', # 0 'JournalLib', # 1 'EcritureNum', # 2 'EcritureDate', # 3 'CompteNum', # 4 'CompteLib', # 5 'CompAuxNum', # 6 We use partner.id 'CompAuxLib', # 7 'PieceRef', # 8 'PieceDate', # 9 'EcritureLib', # 10 'Debit', # 11 'Credit', # 12 'EcritureLet', # 13 'DateLet', # 14 'ValidDate', # 15 'Montantdevise', # 16 'Idevise', # 17 ] company = self.env.user.company_id if not company.vat: raise Warning( _("Missing VAT number for company %s") % company.name) if company.vat[0:2] != 'FR': raise Warning( _("FEC is for French companies only !")) fecfile = StringIO.StringIO() w = csv.writer(fecfile, delimiter='|') w.writerow(header) # INITIAL BALANCE sql_query = ''' SELECT 'OUV' AS JournalCode, 'Balance initiale' AS JournalLib, 'Balance initiale ' || MIN(aa.name) AS EcritureNum, %s AS EcritureDate, MIN(aa.code) AS CompteNum, replace(MIN(aa.name), '|', '/') AS CompteLib, '' AS CompAuxNum, '' AS CompAuxLib, '-' AS PieceRef, %s AS PieceDate, '/' AS EcritureLib, replace(CASE WHEN sum(aml.balance) <= 0 THEN '0,00' ELSE to_char(SUM(aml.balance), '999999999999999D99') END, '.', ',') AS Debit, replace(CASE WHEN sum(aml.balance) >= 0 THEN '0,00' ELSE to_char(-SUM(aml.balance), '999999999999999D99') END, '.', ',') AS Credit, '' AS EcritureLet, '' AS DateLet, %s AS ValidDate, '' AS Montantdevise, '' AS Idevise FROM account_move_line aml LEFT JOIN account_move am ON am.id=aml.move_id JOIN account_account aa ON aa.id = aml.account_id WHERE am.date < %s AND am.company_id = %s AND (aml.debit != 0 OR aml.credit != 0) ''' # For official report: only use posted entries if self.export_type == "official": sql_query += ''' AND am.state = 'posted' ''' sql_query += ''' GROUP BY aml.account_id ''' formatted_date_from = self.date_from.replace('-', '') self._cr.execute( sql_query, (formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id)) for row in self._cr.fetchall(): listrow = list(row) w.writerow([s.encode("utf-8") for s in listrow]) # LINES sql_query = ''' SELECT replace(aj.code, '|', '/') AS JournalCode, replace(aj.name, '|', '/') AS JournalLib, replace(am.name, '|', '/') AS EcritureNum, TO_CHAR(am.date, 'YYYYMMDD') AS EcritureDate, aa.code AS CompteNum, replace(aa.name, '|', '/') AS CompteLib, CASE WHEN rp.ref IS null OR rp.ref = '' THEN COALESCE('ID ' || rp.id, '') ELSE rp.ref END AS CompAuxNum, COALESCE(replace(rp.name, '|', '/'), '') AS CompAuxLib, CASE WHEN am.ref IS null OR am.ref = '' THEN '-' ELSE replace(am.ref, '|', '/') END AS PieceRef, TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate, CASE WHEN aml.name IS NULL THEN '/' ELSE replace(aml.name, '|', '/') END AS EcritureLib, replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE to_char(aml.debit, '999999999999999D99') END, '.', ',') AS Debit, replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE to_char(aml.credit, '999999999999999D99') END, '.', ',') AS Credit, CASE WHEN rec.name IS NULL THEN '' ELSE rec.name END AS EcritureLet, CASE WHEN aml.full_reconcile_id IS NULL THEN '' ELSE TO_CHAR(rec.create_date, 'YYYYMMDD') END AS DateLet, TO_CHAR(am.date, 'YYYYMMDD') AS ValidDate, CASE WHEN aml.amount_currency IS NULL OR aml.amount_currency = 0 THEN '' ELSE replace(to_char(aml.amount_currency, '999999999999999D99'), '.', ',') END AS Montantdevise, CASE WHEN aml.currency_id IS NULL THEN '' ELSE rc.name END AS Idevise FROM account_move_line aml LEFT JOIN account_move am ON am.id=aml.move_id LEFT JOIN res_partner rp ON rp.id=aml.partner_id JOIN account_journal aj ON aj.id = am.journal_id JOIN account_account aa ON aa.id = aml.account_id LEFT JOIN res_currency rc ON rc.id = aml.currency_id LEFT JOIN account_full_reconcile rec ON rec.id = aml.full_reconcile_id WHERE am.date >= %s AND am.date <= %s AND am.company_id = %s AND (aml.debit != 0 OR aml.credit != 0) ''' # For official report: only use posted entries if self.export_type == "official": sql_query += ''' AND am.state = 'posted' ''' sql_query += ''' ORDER BY am.date, am.name, aml.id ''' self._cr.execute( sql_query, (self.date_from, self.date_to, company.id)) for row in self._cr.fetchall(): listrow = list(row) w.writerow([s.encode("utf-8") for s in listrow]) siren = company.vat[4:13] end_date = self.date_to.replace('-', '') suffix = '' if self.export_type == "nonofficial": suffix = '-NONOFFICIAL' fecvalue = fecfile.getvalue() self.write({ 'fec_data': base64.encodestring(fecvalue), # Filename = <siren>FECYYYYMMDD where YYYMMDD is the closing date 'filename': '%sFEC%s%s.csv' % (siren, end_date, suffix), }) fecfile.close() action = { 'name': 'FEC', 'type': 'ir.actions.act_url', 'url': "web/content/?model=account.fr.fec&id=" + str(self.id) + "&filename_field=filename&field=fec_data&download=true&filename=" + self.filename, 'target': 'self', } return action
class ComunicazioneLiquidazione(models.Model): _name = 'comunicazione.liquidazione' _description = 'Comunicazione Liquidazione IVA' @api.model def _default_company(self): company_id = self._context.get('company_id', self.env.user.company_id.id) return company_id @api.constrains('identificativo') def _check_identificativo(self): domain = [('identificativo', '=', self.identificativo)] dichiarazioni = self.search(domain) if len(dichiarazioni) > 1: raise ValidationError( _("Dichiarazione già esiste con identificativo {}").format( self.identificativo)) @api.multi def _compute_name(self): for dich in self: name = "" for quadro in dich.quadri_vp_ids: if not name: period_type = '' if quadro.period_type == 'month': period_type = _('month') else: period_type = _('quarter') name += '{} {}'.format(str(dich.year), period_type) if quadro.period_type == 'month': name += ', {}'.format(str(quadro.month)) else: name += ', {}'.format(str(quadro.quarter)) dich.name = name def _get_identificativo(self): dichiarazioni = self.search([]) if dichiarazioni: return len(dichiarazioni) + 1 else: return 1 company_id = fields.Many2one('res.company', string='Company', required=True, default=_default_company) identificativo = fields.Integer(string='Identificativo', default=_get_identificativo) name = fields.Char(string='Name', compute="_compute_name") year = fields.Integer(string='Year', required=True, size=4) last_month = fields.Integer(string='Last month') liquidazione_del_gruppo = fields.Boolean(string='Liquidazione del gruppo') taxpayer_vat = fields.Char(string='Vat', required=True) controller_vat = fields.Char(string='Controller Vat') taxpayer_fiscalcode = fields.Char(string='Fiscalcode') declarant_different = fields.Boolean( string='Declarant different from taxpayer') declarant_fiscalcode = fields.Char(string='Fiscalcode') declarant_fiscalcode_company = fields.Char(string='Fiscalcode company') codice_carica_id = fields.Many2one('codice.carica', string='Codice carica') declarant_sign = fields.Boolean(string='Declarant sign', default=True) delegate_fiscalcode = fields.Char(string='Fiscalcode') delegate_commitment = fields.Selection( [('1', 'Comunicazione è stata predisposta dal contribuente '), ('2', 'Comunicazione è stata predisposta da chi effettua l’invio')], string='Commitment') delegate_sign = fields.Boolean(string='Delegate sign') date_commitment = fields.Date(string='Date commitment') quadri_vp_ids = fields.One2many('comunicazione.liquidazione.vp', 'comunicazione_id', string="Quadri VP") iva_da_versare = fields.Float(string='IVA da versare', readonly=True) iva_a_credito = fields.Float(string='IVA a credito', readonly=True) @api.model def create(self, vals): comunicazione = super(ComunicazioneLiquidazione, self).create(vals) comunicazione._validate() return comunicazione @api.multi def write(self, vals): super(ComunicazioneLiquidazione, self).write(vals) for comunicazione in self: comunicazione._validate() return True @api.onchange('company_id') def onchange_company_id(self): if self.company_id: if self.company_id.partner_id.vat: self.taxpayer_vat = self.company_id.partner_id.vat[2:] else: self.taxpayer_vat = '' self.taxpayer_fiscalcode = \ self.company_id.partner_id.fiscalcode def get_export_xml(self): self._validate() x1_Fornitura = self._export_xml_get_fornitura() x1_1_Intestazione = self._export_xml_get_intestazione() attrs = {'identificativo': str(self.identificativo).zfill(5)} x1_2_Comunicazione = etree.Element(etree.QName(NS_IV, "Comunicazione"), attrs) x1_2_1_Frontespizio = self._export_xml_get_frontespizio() x1_2_Comunicazione.append(x1_2_1_Frontespizio) x1_2_2_DatiContabili = etree.Element( etree.QName(NS_IV, "DatiContabili")) nr_modulo = 0 for quadro in self.quadri_vp_ids: nr_modulo += 1 modulo = self.with_context(nr_modulo=nr_modulo)\ ._export_xml_get_dati_modulo(quadro) x1_2_2_DatiContabili.append(modulo) x1_2_Comunicazione.append(x1_2_2_DatiContabili) # Composizione struttura xml con le varie sezioni generate x1_Fornitura.append(x1_1_Intestazione) x1_Fornitura.append(x1_2_Comunicazione) xml_string = etree.tostring(x1_Fornitura, encoding='utf8', method='xml', pretty_print=True) return xml_string def _validate(self): """ Controllo congruità dati della comunicazione """ # Anno obbligatorio if not self.year: raise ValidationError(_("Year required")) # Codice Fiscale if not self.taxpayer_fiscalcode \ or len(self.taxpayer_fiscalcode) not in [11, 16]: raise ValidationError( _("Taxpayer Fiscalcode is required. It's accepted codes \ with lenght 11 or 16 chars")) # Codice Fiscale dichiarante Obbligatorio se il codice fiscale # del contribuente è di 11 caratteri if self.taxpayer_fiscalcode and len(self.taxpayer_fiscalcode) == 11\ and not self.declarant_fiscalcode: raise ValidationError( _("Declarant Fiscalcode is required. You can enable the \ section with different declarant option")) # LiquidazioneGruppo: elemento opzionale, di tipo DatoCB_Type. # Se presente non deve essere presente l’elemento PIVAControllante. # Non può essere presente se l’elemento CodiceFiscale è lungo 16 # caratteri. if self.liquidazione_del_gruppo: if self.controller_vat: raise ValidationError( _("Per liquidazione del gruppo, partita iva controllante\ deve essere vuota")) if len(self.taxpayer_fiscalcode) == 16: raise ValidationError( _("Liquidazione del gruppo non valida, visto il codice\ fiscale di 16 caratteri")) # CodiceCaricaDichiarante if self.declarant_fiscalcode: if not self.codice_carica_id: raise ValidationError( _("Indicare il codice carica del dichiarante")) # CodiceFiscaleSocieta: # Obbligatori per codice carica 9 if self.codice_carica_id and self.codice_carica_id.code == '9': if not self.declarant_fiscalcode_company: raise ValidationError( _("Visto il codice carica, occorre indicare il codice \ fiscale della socità dichiarante")) # ImpegnoPresentazione:: if self.delegate_fiscalcode: if not self.delegate_commitment: raise ValidationError( _("Visto il codice fiscale dell'intermediario, occorre \ indicare il codice l'impegno")) if not self.date_commitment: raise ValidationError( _("Visto il codice fiscale dell'intermediario, occorre \ indicare la data dell'impegno")) # ImpegnoPresentazione:: if self.delegate_fiscalcode and not self.delegate_sign: raise ValidationError( _("In presenza dell'incaricato nella sezione impegno \ alla presentazione telematica, è necessario vistare \ l'opzione firma dell'incaricato")) return True def _export_xml_get_fornitura(self): x1_Fornitura = etree.Element(etree.QName(NS_IV, "Fornitura"), nsmap=NS_MAP) return x1_Fornitura def _export_xml_validate(self): return True def _export_xml_get_intestazione(self): x1_1_Intestazione = etree.Element(etree.QName(NS_IV, "Intestazione")) # Codice Fornitura x1_1_1_CodiceFornitura = etree.SubElement( x1_1_Intestazione, etree.QName(NS_IV, "CodiceFornitura")) code = str(self.year)[-2:] x1_1_1_CodiceFornitura.text = unicode('IVP{}'.format(code)) # Codice Fiscale Dichiarante if self.declarant_fiscalcode: x1_1_2_CodiceFiscaleDichiarante = etree.SubElement( x1_1_Intestazione, etree.QName(NS_IV, "CodiceFiscaleDichiarante")) x1_1_2_CodiceFiscaleDichiarante.text = unicode( self.declarant_fiscalcode) # Codice Carica if self.codice_carica_id: x1_1_3_CodiceCarica = etree.SubElement( x1_1_Intestazione, etree.QName(NS_IV, "CodiceCarica")) x1_1_3_CodiceCarica.text = unicode(self.codice_carica_id.code) return x1_1_Intestazione def _export_xml_get_frontespizio(self): x1_2_1_Frontespizio = etree.Element(etree.QName(NS_IV, "Frontespizio")) # Codice Fiscale x1_2_1_1_CodiceFiscale = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "CodiceFiscale")) x1_2_1_1_CodiceFiscale.text = unicode(self.taxpayer_fiscalcode) \ if self.taxpayer_fiscalcode else '' # Anno Imposta x1_2_1_2_AnnoImposta = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "AnnoImposta")) x1_2_1_2_AnnoImposta.text = str(self.year) # Partita IVA x1_2_1_3_PartitaIVA = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "PartitaIVA")) x1_2_1_3_PartitaIVA.text = self.taxpayer_vat # PIVA Controllante if self.controller_vat: x1_2_1_4_PIVAControllante = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "PIVAControllante")) x1_2_1_4_PIVAControllante.text = self.controller_vat # Ultimo Mese if self.last_month: x1_2_1_5_UltimoMese = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "UltimoMese")) x1_2_1_5_UltimoMese.text = self.last_month # Liquidazione Gruppo x1_2_1_6_LiquidazioneGruppo = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "LiquidazioneGruppo")) x1_2_1_6_LiquidazioneGruppo.text = \ '1' if self.liquidazione_del_gruppo else '0' # CF Dichiarante if self.declarant_fiscalcode: x1_2_1_7_CFDichiarante = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "CFDichiarante")) x1_2_1_7_CFDichiarante.text = self.declarant_fiscalcode # CodiceCaricaDichiarante if self.codice_carica_id: x1_2_1_8_CodiceCaricaDichiarante = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "CodiceCaricaDichiarante")) x1_2_1_8_CodiceCaricaDichiarante.text = self.codice_carica_id.code # CodiceFiscaleSocieta if self.declarant_fiscalcode_company: x1_2_1_9_CodiceFiscaleSocieta = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "CodiceFiscaleSocieta")) x1_2_1_9_CodiceFiscaleSocieta.text =\ self.declarant_fiscalcode_company.code # FirmaDichiarazione x1_2_1_10_FirmaDichiarazione = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "FirmaDichiarazione")) x1_2_1_10_FirmaDichiarazione.text = '1' if self.declarant_sign else '0' # CFIntermediario if self.delegate_fiscalcode: x1_2_1_11_CFIntermediario = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "CFIntermediario")) x1_2_1_11_CFIntermediario.text = self.delegate_fiscalcode # ImpegnoPresentazione if self.delegate_commitment: x1_2_1_12_ImpegnoPresentazione = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "ImpegnoPresentazione")) x1_2_1_12_ImpegnoPresentazione.text = self.delegate_commitment # DataImpegno if self.date_commitment: x1_2_1_13_DataImpegno = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "DataImpegno")) x1_2_1_13_DataImpegno.text = datetime.strptime( self.date_commitment, "%Y-%m-%d").strftime('%d%m%Y') # FirmaIntermediario if self.delegate_fiscalcode: x1_2_1_14_FirmaIntermediario = etree.SubElement( x1_2_1_Frontespizio, etree.QName(NS_IV, "FirmaIntermediario")) x1_2_1_14_FirmaIntermediario.text =\ '1' if self.delegate_sign else '0' return x1_2_1_Frontespizio def _export_xml_get_dati_modulo(self, quadro): # 1.2.2.1 Modulo xModulo = etree.Element(etree.QName(NS_IV, "Modulo")) # Numero Modulo NumeroModulo = etree.SubElement(xModulo, etree.QName(NS_IV, "NumeroModulo")) NumeroModulo.text = str(self._context.get('nr_modulo', 1)) if quadro.period_type == 'month': # 1.2.2.1.1 Mese Mese = etree.SubElement(xModulo, etree.QName(NS_IV, "Mese")) Mese.text = str(quadro.month) else: # 1.2.2.1.2 Trimestre Trimestre = etree.SubElement(xModulo, etree.QName(NS_IV, "Trimestre")) Trimestre.text = str(quadro.quarter) # Da escludere per liquidazione del gruppo if not self.liquidazione_del_gruppo: # 1.2.2.1.3 Subfornitura if quadro.subcontracting: Subfornitura = etree.SubElement( xModulo, etree.QName(NS_IV, "Subfornitura")) Subfornitura.text = '1' if quadro.subcontracting \ else '0' # 1.2.2.1.4 EventiEccezionali if quadro.exceptional_events: EventiEccezionali = etree.SubElement( xModulo, etree.QName(NS_IV, "EventiEccezionali")) EventiEccezionali.text = quadro.exceptional_events # 1.2.2.1.5 TotaleOperazioniAttive TotaleOperazioniAttive = etree.SubElement( xModulo, etree.QName(NS_IV, "TotaleOperazioniAttive")) TotaleOperazioniAttive.text = "{:.2f}"\ .format(quadro.imponibile_operazioni_attive).replace('.', ',') # 1.2.2.1.6 TotaleOperazioniPassive TotaleOperazioniPassive = etree.SubElement( xModulo, etree.QName(NS_IV, "TotaleOperazioniPassive")) TotaleOperazioniPassive.text = "{:.2f}"\ .format(quadro.imponibile_operazioni_passive).replace('.', ',') # 1.2.2.1.7 IvaEsigibile IvaEsigibile = etree.SubElement(xModulo, etree.QName(NS_IV, "IvaEsigibile")) IvaEsigibile.text = "{:.2f}".format(quadro.iva_esigibile)\ .replace('.', ',') # 1.2.2.1.8 IvaDetratta IvaDetratta = etree.SubElement(xModulo, etree.QName(NS_IV, "IvaDetratta")) IvaDetratta.text = "{:.2f}".format(quadro.iva_detratta)\ .replace('.', ',') # 1.2.2.1.9 IvaDovuta if quadro.iva_dovuta_debito: IvaDovuta = etree.SubElement(xModulo, etree.QName(NS_IV, "IvaDovuta")) IvaDovuta.text = "{:.2f}".format(quadro.iva_dovuta_debito)\ .replace('.', ',') # 1.2.2.1.10 IvaCredito if quadro.iva_dovuta_credito: IvaCredito = etree.SubElement(xModulo, etree.QName(NS_IV, "IvaCredito")) IvaCredito.text = "{:.2f}".format(quadro.iva_dovuta_credito)\ .replace('.', ',') # 1.2.2.1.11 DebitoPrecedente DebitoPrecedente = etree.SubElement( xModulo, etree.QName(NS_IV, "DebitoPrecedente")) DebitoPrecedente.text = "{:.2f}".format( quadro.debito_periodo_precedente).replace('.', ',') # 1.2.2.1.12 CreditoPeriodoPrecedente CreditoPeriodoPrecedente = etree.SubElement( xModulo, etree.QName(NS_IV, "CreditoPeriodoPrecedente")) CreditoPeriodoPrecedente.text = "{:.2f}".format( quadro.credito_periodo_precedente).replace('.', ',') # 1.2.2.1.13 CreditoAnnoPrecedente CreditoAnnoPrecedente = etree.SubElement( xModulo, etree.QName(NS_IV, "CreditoAnnoPrecedente")) CreditoAnnoPrecedente.text = "{:.2f}".format( quadro.credito_anno_precedente).replace('.', ',') # 1.2.2.1.14 VersamentiAutoUE VersamentiAutoUE = etree.SubElement( xModulo, etree.QName(NS_IV, "VersamentiAutoUE")) VersamentiAutoUE.text = "{:.2f}".format( quadro.versamento_auto_UE).replace('.', ',') # 1.2.2.1.15 CreditiImposta CreditiImposta = etree.SubElement(xModulo, etree.QName(NS_IV, "CreditiImposta")) CreditiImposta.text = "{:.2f}".format(quadro.crediti_imposta).replace( '.', ',') # 1.2.2.1.16 InteressiDovuti InteressiDovuti = etree.SubElement( xModulo, etree.QName(NS_IV, "InteressiDovuti")) InteressiDovuti.text = "{:.2f}".format( quadro.interessi_dovuti).replace('.', ',') # 1.2.2.1.17 Acconto Acconto = etree.SubElement(xModulo, etree.QName(NS_IV, "Acconto")) Acconto.text = "{:.2f}".format(quadro.accounto_dovuto).replace( '.', ',') # 1.2.2.1.18 ImportoDaVersare ImportoDaVersare = etree.SubElement( xModulo, etree.QName(NS_IV, "ImportoDaVersare")) ImportoDaVersare.text = "{:.2f}".format(quadro.iva_da_versare).replace( '.', ',') # 1.2.2.1.19 ImportoACredito ImportoACredito = etree.SubElement( xModulo, etree.QName(NS_IV, "ImportoACredito")) ImportoACredito.text = "{:.2f}".format(quadro.iva_a_credito).replace( '.', ',') return xModulo
class SaleOrderLine(models.Model): _name = 'sale.order.line' _description = 'Sales Order Line' _order = 'order_id desc, sequence, id' @api.depends('state', 'product_uom_qty', 'qty_delivered', 'qty_to_invoice', 'qty_invoiced') def _compute_invoice_status(self): """ Compute the invoice status of a SO line. Possible statuses: - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to invoice. This is also hte default value if the conditions of no other status is met. - to invoice: we refer to the quantity to invoice of the line. Refer to method `_get_to_invoice_qty()` for more information on how this quantity is calculated. - upselling: this is possible only for a product invoiced on ordered quantities for which we delivered more than expected. The could arise if, for example, a project took more time than expected but we decided not to invoice the extra cost to the client. This occurs onyl in state 'sale', so that when a SO is set to done, the upselling opportunity is removed from the list. - invoiced: the quantity invoiced is larger or equal to the quantity ordered. """ precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for line in self: if line.state not in ('sale', 'done'): line.invoice_status = 'no' elif not float_is_zero(line.qty_to_invoice, precision_digits=precision): line.invoice_status = 'to invoice' elif line.state == 'sale' and line.product_id.invoice_policy == 'order' and\ float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) == 1: line.invoice_status = 'upselling' elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) >= 0: line.invoice_status = 'invoiced' else: line.invoice_status = 'no' @api.depends('product_uom_qty', 'discount', 'price_unit', 'tax_id') def _compute_amount(self): """ Compute the amounts of the SO line. """ for line in self: price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_id) line.update({ 'price_tax': taxes['total_included'] - taxes['total_excluded'], 'price_total': taxes['total_included'], 'price_subtotal': taxes['total_excluded'], }) @api.depends('product_id.invoice_policy', 'order_id.state') def _compute_qty_delivered_updateable(self): for line in self: line.qty_delivered_updateable = line.product_id.invoice_policy in ( 'order', 'delivery' ) and line.order_id.state == 'sale' and line.product_id.track_service == 'manual' @api.depends('qty_invoiced', 'qty_delivered', 'product_uom_qty', 'order_id.state') def _get_to_invoice_qty(self): """ Compute the quantity to invoice. If the invoice policy is order, the quantity to invoice is calculated from the ordered quantity. Otherwise, the quantity delivered is used. """ for line in self: if line.order_id.state in ['sale', 'done']: if line.product_id.invoice_policy == 'order': line.qty_to_invoice = line.product_uom_qty - line.qty_invoiced else: line.qty_to_invoice = line.qty_delivered - line.qty_invoiced else: line.qty_to_invoice = 0 @api.depends('invoice_lines.invoice_id.state', 'invoice_lines.quantity') def _get_invoice_qty(self): """ Compute the quantity invoiced. If case of a refund, the quantity invoiced is decreased. Note that this is the case only if the refund is generated from the SO and that is intentional: if a refund made would automatically decrease the invoiced quantity, then there is a risk of reinvoicing it automatically, which may not be wanted at all. That's why the refund has to be created from the SO """ for line in self: qty_invoiced = 0.0 for invoice_line in line.invoice_lines: if invoice_line.invoice_id.state != 'cancel': if invoice_line.invoice_id.type == 'out_invoice': qty_invoiced += invoice_line.quantity elif invoice_line.invoice_id.type == 'out_refund': qty_invoiced -= invoice_line.quantity line.qty_invoiced = qty_invoiced @api.depends('price_subtotal', 'product_uom_qty') def _get_price_reduce(self): for line in self: line.price_reduce = line.price_subtotal / line.product_uom_qty if line.product_uom_qty else 0.0 @api.multi def _compute_tax_id(self): for line in self: fpos = line.order_id.fiscal_position_id or line.order_id.partner_id.property_account_position_id if fpos: # The superuser is used by website_sale in order to create a sale order. We need to make # sure we only select the taxes related to the company of the partner. This should only # apply if the partner is linked to a company. if self.env.uid == SUPERUSER_ID and line.order_id.company_id: taxes = fpos.map_tax(line.product_id.taxes_id).filtered( lambda r: r.company_id == line.order_id.company_id) else: taxes = fpos.map_tax(line.product_id.taxes_id) line.tax_id = taxes else: line.tax_id = line.product_id.taxes_id if line.product_id.taxes_id else False @api.multi def _prepare_order_line_procurement(self, group_id=False): self.ensure_one() return { 'name': self.name, 'origin': self.order_id.name, 'date_planned': datetime.strptime(self.order_id.date_order, DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(days=self.customer_lead), 'product_id': self.product_id.id, 'product_qty': self.product_uom_qty, 'product_uom': self.product_uom.id, 'company_id': self.order_id.company_id.id, 'group_id': group_id, 'sale_line_id': self.id } @api.multi def _action_procurement_create(self): """ Create procurements based on quantity ordered. If the quantity is increased, new procurements are created. If the quantity is decreased, no automated action is taken. """ precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') new_procs = self.env['procurement.order'] #Empty recordset for line in self: if line.state != 'sale' or not line.product_id._need_procurement(): continue qty = 0.0 for proc in line.procurement_ids: qty += proc.product_qty if float_compare(qty, line.product_uom_qty, precision_digits=precision) >= 0: return False if not line.order_id.procurement_group_id: vals = line.order_id._prepare_procurement_group() line.order_id.procurement_group_id = self.env[ "procurement.group"].create(vals) vals = line._prepare_order_line_procurement( group_id=line.order_id.procurement_group_id.id) vals['product_qty'] = line.product_uom_qty - qty new_proc = self.env["procurement.order"].create(vals) new_procs += new_proc new_procs.run() return new_procs @api.model def _get_analytic_invoice_policy(self): return ['cost'] @api.model def _get_analytic_track_service(self): return [] @api.model def create(self, values): line = super(SaleOrderLine, self).create(values) if line.state == 'sale': if line.product_id.track_service in self._get_analytic_track_service( ) or line.product_id.invoice_policy in self._get_analytic_invoice_policy( ) and not line.order_id.project_id: line.order_id._create_analytic_account() line._action_procurement_create() return line @api.multi def write(self, values): lines = False if 'product_uom_qty' in values: precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') lines = self.filtered( lambda r: r.state == 'sale' and float_compare( r.product_uom_qty, values['product_uom_qty'], precision_digits=precision) == -1) result = super(SaleOrderLine, self).write(values) if lines: lines._action_procurement_create() return result order_id = fields.Many2one('sale.order', string='Order Reference', required=True, ondelete='cascade', index=True, copy=False) name = fields.Text(string='Description', required=True) sequence = fields.Integer(string='Sequence', default=10) invoice_lines = fields.Many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_line_id', string='Invoice Lines', copy=False) invoice_status = fields.Selection([('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice')], string='Invoice Status', compute='_compute_invoice_status', store=True, readonly=True, default='no') price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price'), default=0.0) price_subtotal = fields.Monetary(compute='_compute_amount', string='Subtotal', readonly=True, store=True) price_tax = fields.Monetary(compute='_compute_amount', string='Taxes', readonly=True, store=True) price_total = fields.Monetary(compute='_compute_amount', string='Total', readonly=True, store=True) price_reduce = fields.Monetary(compute='_get_price_reduce', string='Price Reduce', readonly=True, store=True) tax_id = fields.Many2many('account.tax', string='Taxes') discount = fields.Float(string='Discount (%)', digits=dp.get_precision('Discount'), default=0.0) product_id = fields.Many2one('product.product', string='Product', domain=[('sale_ok', '=', True)], change_default=True, ondelete='restrict', required=True) product_uom_qty = fields.Float( string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True, default=1.0) product_uom = fields.Many2one('product.uom', string='Unit of Measure', required=True) qty_delivered_updateable = fields.Boolean( compute='_compute_qty_delivered_updateable', string='Can Edit Delivered', readonly=True, default=True) qty_delivered = fields.Float( string='Delivered', copy=False, digits=dp.get_precision('Product Unit of Measure'), default=0.0) qty_to_invoice = fields.Float( compute='_get_to_invoice_qty', string='To Invoice', store=True, readonly=True, digits=dp.get_precision('Product Unit of Measure'), default=0.0) qty_invoiced = fields.Float( compute='_get_invoice_qty', string='Invoiced', store=True, readonly=True, digits=dp.get_precision('Product Unit of Measure'), default=0.0) salesman_id = fields.Many2one(related='order_id.user_id', store=True, string='Salesperson', readonly=True) currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True) company_id = fields.Many2one(related='order_id.company_id', string='Company', store=True, readonly=True) order_partner_id = fields.Many2one(related='order_id.partner_id', store=True, string='Customer') state = fields.Selection([ ('draft', 'Quotation'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Done'), ('cancel', 'Cancelled'), ], related='order_id.state', string='Order Status', readonly=True, copy=False, store=True, default='draft') customer_lead = fields.Float( 'Delivery Lead Time', required=True, default=0.0, help= "Number of days between the order confirmation and the shipping of the products to the customer", oldname="delay") procurement_ids = fields.One2many('procurement.order', 'sale_line_id', string='Procurements') @api.multi def _prepare_invoice_line(self, qty): """ Prepare the dict of values to create the new invoice line for a sales order line. :param qty: float quantity to invoice """ self.ensure_one() res = {} account = self.product_id.property_account_income_id or self.product_id.categ_id.property_account_income_categ_id if not account: raise UserError(_('Please define income account for this product: "%s" (id:%d) - or for its category: "%s".') % \ (self.product_id.name, self.product_id.id, self.product_id.categ_id.name)) fpos = self.order_id.fiscal_position_id or self.order_id.partner_id.property_account_position_id if fpos: account = fpos.map_account(account) res = { 'name': self.name, 'sequence': self.sequence, 'origin': self.order_id.name, 'account_id': account.id, 'price_unit': self.price_unit, 'quantity': qty, 'discount': self.discount, 'uom_id': self.product_uom.id, 'product_id': self.product_id.id or False, 'invoice_line_tax_ids': [(6, 0, self.tax_id.ids)], 'account_analytic_id': self.order_id.project_id.id, } return res @api.multi def invoice_line_create(self, invoice_id, qty): """ Create an invoice line. The quantity to invoice can be positive (invoice) or negative (refund). :param invoice_id: integer :param qty: float quantity to invoice """ precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') for line in self: if not float_is_zero(qty, precision_digits=precision): vals = line._prepare_invoice_line(qty=qty) vals.update({ 'invoice_id': invoice_id, 'sale_line_ids': [(6, 0, [line.id])] }) self.env['account.invoice.line'].create(vals) @api.multi @api.onchange('product_id') def product_id_change(self): if not self.product_id: return {'domain': {'product_uom': []}} vals = {} domain = { 'product_uom': [('category_id', '=', self.product_id.uom_id.category_id.id)] } if not (self.product_uom and (self.product_id.uom_id.category_id.id == self.product_uom.category_id.id)): vals['product_uom'] = self.product_id.uom_id product = self.product_id.with_context( lang=self.order_id.partner_id.lang, partner=self.order_id.partner_id.id, quantity=self.product_uom_qty, date=self.order_id.date_order, pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id) name = product.name_get()[0][1] if product.description_sale: name += '\n' + product.description_sale vals['name'] = name self._compute_tax_id() if self.order_id.pricelist_id and self.order_id.partner_id: vals['price_unit'] = self.env[ 'account.tax']._fix_tax_included_price(product.price, product.taxes_id, self.tax_id) self.update(vals) return {'domain': domain} @api.onchange('product_uom', 'product_uom_qty') def product_uom_change(self): if not self.product_uom: self.price_unit = 0.0 return if self.order_id.pricelist_id and self.order_id.partner_id: product = self.product_id.with_context( lang=self.order_id.partner_id.lang, partner=self.order_id.partner_id.id, quantity=self.product_uom_qty, date_order=self.order_id.date_order, pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id) self.price_unit = self.env['account.tax']._fix_tax_included_price( product.price, product.taxes_id, self.tax_id) @api.multi def unlink(self): if self.filtered(lambda x: x.state in ('sale', 'done')): raise UserError( _('You can not remove a sale order line.\nDiscard changes and try setting the quantity to 0.' )) return super(SaleOrderLine, self).unlink() @api.multi def _get_delivered_qty(self): ''' Intended to be overridden in sale_stock and sale_mrp :return: the quantity delivered :rtype: float ''' return 0.0
class SaleOrder(models.Model): _name = "sale.order" _inherit = ['mail.thread', 'ir.needaction_mixin'] _description = "Sales Order" _order = 'date_order desc, id desc' @api.depends('order_line.price_total') def _amount_all(self): """ Compute the total amounts of the SO. """ for order in self: amount_untaxed = amount_tax = 0.0 for line in order.order_line: amount_untaxed += line.price_subtotal amount_tax += line.price_tax order.update({ 'amount_untaxed': order.pricelist_id.currency_id.round(amount_untaxed), 'amount_tax': order.pricelist_id.currency_id.round(amount_tax), 'amount_total': amount_untaxed + amount_tax, }) @api.depends('state', 'order_line.invoice_status') def _get_invoiced(self): """ Compute the invoice status of a SO. Possible statuses: - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to invoice. This is also hte default value if the conditions of no other status is met. - to invoice: if any SO line is 'to invoice', the whole SO is 'to invoice' - invoiced: if all SO lines are invoiced, the SO is invoiced. - upselling: if all SO lines are invoiced or upselling, the status is upselling. The invoice_ids are obtained thanks to the invoice lines of the SO lines, and we also search for possible refunds created directly from existing invoices. This is necessary since such a refund is not directly linked to the SO. """ for order in self: invoice_ids = order.order_line.mapped('invoice_lines').mapped( 'invoice_id') # Search for refunds as well refund_ids = self.env['account.invoice'].browse() if invoice_ids: refund_ids = refund_ids.search([ ('type', '=', 'out_refund'), ('origin', 'in', invoice_ids.mapped('number')) ]) line_invoice_status = [ line.invoice_status for line in order.order_line ] if order.state not in ('sale', 'done'): invoice_status = 'no' elif any(invoice_status == 'to invoice' for invoice_status in line_invoice_status): invoice_status = 'to invoice' elif all(invoice_status == 'invoiced' for invoice_status in line_invoice_status): invoice_status = 'invoiced' elif all(invoice_status in ['invoiced', 'upselling'] for invoice_status in line_invoice_status): invoice_status = 'upselling' else: invoice_status = 'no' order.update({ 'invoice_count': len(set(invoice_ids.ids + refund_ids.ids)), 'invoice_ids': invoice_ids.ids + refund_ids.ids, 'invoice_status': invoice_status }) @api.model def _default_note(self): return self.env.user.company_id.sale_note @api.model def _get_default_team(self): default_team_id = self.env['crm.team']._get_default_team_id() return self.env['crm.team'].browse(default_team_id) @api.onchange('fiscal_position_id') def _compute_tax_id(self): """ Trigger the recompute of the taxes if the fiscal position is changed on the SO. """ for order in self: order.order_line._compute_tax_id() name = fields.Char(string='Order Reference', required=True, copy=False, readonly=True, index=True, default='New') origin = fields.Char( string='Source Document', help= "Reference of the document that generated this sales order request.") client_order_ref = fields.Char(string='Customer Reference', copy=False) state = fields.Selection([ ('draft', 'Quotation'), ('sent', 'Quotation Sent'), ('sale', 'Sale Order'), ('done', 'Done'), ('cancel', 'Cancelled'), ], string='Status', readonly=True, copy=False, index=True, track_visibility='onchange', default='draft') date_order = fields.Datetime(string='Order Date', required=True, readonly=True, index=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, copy=False, default=fields.Datetime.now) validity_date = fields.Date(string='Expiration Date', readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }) create_date = fields.Datetime(string='Creation Date', readonly=True, index=True, help="Date on which sales order is created.") user_id = fields.Many2one('res.users', string='Salesperson', index=True, track_visibility='onchange', default=lambda self: self.env.user) partner_id = fields.Many2one('res.partner', string='Customer', readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, required=True, change_default=True, index=True, track_visibility='always') partner_invoice_id = fields.Many2one( 'res.partner', string='Invoice Address', readonly=True, required=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help="Invoice address for current sales order.") partner_shipping_id = fields.Many2one( 'res.partner', string='Delivery Address', readonly=True, required=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help="Delivery address for current sales order.") pricelist_id = fields.Many2one('product.pricelist', string='Pricelist', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help="Pricelist for current sales order.") currency_id = fields.Many2one("res.currency", related='pricelist_id.currency_id', string="Currency", readonly=True, required=True) project_id = fields.Many2one( 'account.analytic.account', 'Analytic Account', readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help="The analytic account related to a sales order.", copy=False) order_line = fields.One2many('sale.order.line', 'order_id', string='Order Lines', states={ 'cancel': [('readonly', True)], 'done': [('readonly', True)] }, copy=True) invoice_count = fields.Integer(string='# of Invoices', compute='_get_invoiced', readonly=True) invoice_ids = fields.Many2many("account.invoice", string='Invoices', compute="_get_invoiced", readonly=True, copy=False) invoice_status = fields.Selection([('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice')], string='Invoice Status', compute='_get_invoiced', store=True, readonly=True, default='no') note = fields.Text('Terms and conditions', default=_default_note) amount_untaxed = fields.Monetary(string='Untaxed Amount', store=True, readonly=True, compute='_amount_all', track_visibility='always') amount_tax = fields.Monetary(string='Taxes', store=True, readonly=True, compute='_amount_all', track_visibility='always') amount_total = fields.Monetary(string='Total', store=True, readonly=True, compute='_amount_all', track_visibility='always') payment_term_id = fields.Many2one('account.payment.term', string='Payment Term', oldname='payment_term') fiscal_position_id = fields.Many2one('account.fiscal.position', oldname='fiscal_position', string='Fiscal Position') company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env['res.company']. _company_default_get('sale.order')) team_id = fields.Many2one('crm.team', 'Sales Team', change_default=True, default=_get_default_team) procurement_group_id = fields.Many2one('procurement.group', 'Procurement Group', copy=False) product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product') @api.multi def button_dummy(self): return True @api.multi def unlink(self): for order in self: if order.state != 'draft': raise UserError(_('You can only delete draft quotations!')) return super(SaleOrder, self).unlink() @api.multi def _track_subtype(self, init_values): self.ensure_one() if 'state' in init_values and self.state == 'sale': return 'sale.mt_order_confirmed' elif 'state' in init_values and self.state == 'sent': return 'sale.mt_order_sent' return super(SaleOrder, self)._track_subtype(init_values) @api.multi @api.onchange('partner_shipping_id') def onchange_partner_shipping_id(self): """ Trigger the change of fiscal position when the shipping address is modified. """ fiscal_position = self.env[ 'account.fiscal.position'].get_fiscal_position( self.partner_id.id, self.partner_shipping_id.id) if fiscal_position: self.fiscal_position_id = fiscal_position return {} @api.multi @api.onchange('partner_id') def onchange_partner_id(self): """ Update the following fields when the partner is changed: - Pricelist - Payment term - Invoice address - Delivery address """ if not self.partner_id: self.update({ 'partner_invoice_id': False, 'partner_shipping_id': False, 'payment_term_id': False, 'fiscal_position_id': False, }) return addr = self.partner_id.address_get(['delivery', 'invoice']) values = { 'pricelist_id': self.partner_id.property_product_pricelist and self.partner_id.property_product_pricelist.id or False, 'payment_term_id': self.partner_id.property_payment_term_id and self.partner_id.property_payment_term_id.id or False, 'partner_invoice_id': addr['invoice'], 'partner_shipping_id': addr['delivery'], 'note': self.with_context( lang=self.partner_id.lang).env.user.company_id.sale_note, } if self.partner_id.user_id: values['user_id'] = self.partner_id.user_id.id if self.partner_id.team_id: values['team_id'] = self.partner_id.team_id.id self.update(values) @api.model def create(self, vals): if vals.get('name', 'New') == 'New': vals['name'] = self.env['ir.sequence'].next_by_code( 'sale.order') or 'New' # Makes sure partner_invoice_id', 'partner_shipping_id' and 'pricelist_id' are defined if any(f not in vals for f in ['partner_invoice_id', 'partner_shipping_id', 'pricelist_id']): partner = self.env['res.partner'].browse(vals.get('partner_id')) addr = partner.address_get(['delivery', 'invoice']) vals['partner_invoice_id'] = vals.setdefault( 'partner_invoice_id', addr['invoice']) vals['partner_shipping_id'] = vals.setdefault( 'partner_shipping_id', addr['delivery']) vals['pricelist_id'] = vals.setdefault( 'pricelist_id', partner.property_product_pricelist and partner.property_product_pricelist.id) result = super(SaleOrder, self).create(vals) return result @api.multi def _prepare_invoice(self): """ Prepare the dict of values to create the new invoice for a sales order. This method may be overridden to implement custom invoice generation (making sure to call super() to establish a clean extension chain). """ self.ensure_one() journal_id = self.env['account.invoice'].default_get(['journal_id' ])['journal_id'] if not journal_id: raise UserError( _('Please define an accounting sale journal for this company.') ) invoice_vals = { 'name': self.client_order_ref or '', 'origin': self.name, 'type': 'out_invoice', 'reference': self.client_order_ref or self.name, 'account_id': self.partner_invoice_id.property_account_receivable_id.id, 'partner_id': self.partner_invoice_id.id, 'journal_id': journal_id, 'currency_id': self.pricelist_id.currency_id.id, 'comment': self.note, 'payment_term_id': self.payment_term_id.id, 'fiscal_position_id': self.fiscal_position_id.id or self.partner_invoice_id.property_account_position_id.id, 'company_id': self.company_id.id, 'user_id': self.user_id and self.user_id.id, 'team_id': self.team_id.id } return invoice_vals @api.multi def print_quotation(self): self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'}) return self.env['report'].get_action(self, 'sale.report_saleorder') @api.multi def action_view_invoice(self): invoice_ids = self.mapped('invoice_ids') imd = self.env['ir.model.data'] action = imd.xmlid_to_object('account.action_invoice_tree1') list_view_id = imd.xmlid_to_res_id('account.invoice_tree') form_view_id = imd.xmlid_to_res_id('account.invoice_form') result = { 'name': action.name, 'help': action.help, 'type': action.type, 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], [False, 'calendar'], [False, 'pivot']], 'target': action.target, 'context': action.context, 'res_model': action.res_model, } if len(invoice_ids) > 1: result['domain'] = "[('id','in',%s)]" % invoice_ids.ids elif len(invoice_ids) == 1: result['views'] = [(form_view_id, 'form')] result['res_id'] = invoice_ids.ids[0] else: result = {'type': 'ir.actions.act_window_close'} return result @api.multi def action_invoice_create(self, grouped=False, final=False): """ Create the invoice associated to the SO. :param grouped: if True, invoices are grouped by SO id. If False, invoices are grouped by (partner, currency) :param final: if True, refunds will be generated if necessary :returns: list of created invoices """ inv_obj = self.env['account.invoice'] precision = self.env['decimal.precision'].precision_get( 'Product Unit of Measure') invoices = {} for order in self: group_key = order.id if grouped else (order.partner_id.id, order.currency_id.id) for line in order.order_line.sorted( key=lambda l: l.qty_to_invoice < 0): if float_is_zero(line.qty_to_invoice, precision_digits=precision): continue if group_key not in invoices: inv_data = order._prepare_invoice() invoice = inv_obj.create(inv_data) invoices[group_key] = invoice elif group_key in invoices and order.name not in invoices[ group_key].origin.split(', '): invoices[group_key].write({ 'origin': invoices[group_key].origin + ', ' + order.name }) if line.qty_to_invoice > 0: line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice) elif line.qty_to_invoice < 0 and final: line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice) for invoice in invoices.values(): # If invoice is negative, do a refund invoice instead if invoice.amount_untaxed < 0: invoice.type = 'out_refund' for line in invoice.invoice_line_ids: line.quantity = -line.quantity # Necessary to force computation of taxes. In account_invoice, they are triggered # by onchanges, which are not triggered when doing a create. invoice.compute_taxes() return [inv.id for inv in invoices.values()] @api.multi def action_draft(self): self.filtered(lambda s: s.state in ['cancel', 'sent']).write( {'state': 'draft'}) @api.multi def action_cancel(self): self.write({'state': 'cancel'}) @api.multi def action_quotation_send(self): ''' This function opens a window to compose an email, with the edi sale template message loaded by default ''' self.ensure_one() ir_model_data = self.env['ir.model.data'] try: template_id = ir_model_data.get_object_reference( 'sale', 'email_template_edi_sale')[1] except ValueError: template_id = False try: compose_form_id = ir_model_data.get_object_reference( 'mail', 'email_compose_message_wizard_form')[1] except ValueError: compose_form_id = False ctx = dict() ctx.update({ 'default_model': 'sale.order', 'default_res_id': self.ids[0], 'default_use_template': bool(template_id), 'default_template_id': template_id, 'default_composition_mode': 'comment', 'mark_so_as_sent': True }) return { 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', 'res_model': 'mail.compose.message', 'views': [(compose_form_id, 'form')], 'view_id': compose_form_id, 'target': 'new', 'context': ctx, } @api.multi def force_quotation_send(self): for order in self: email_act = order.action_quotation_send() if email_act and email_act.get('context'): email_ctx = email_act['context'] email_ctx.update(default_email_from=order.company_id.email) order.with_context(email_ctx).message_post_with_template( email_ctx.get('default_template_id')) return True @api.multi def action_done(self): self.write({'state': 'done'}) @api.model def _prepare_procurement_group(self): return {'name': self.name} @api.multi def action_confirm(self): for order in self: order.state = 'sale' if self.env.context.get('send_email'): self.force_quotation_send() order.order_line._action_procurement_create() if not order.project_id: for line in order.order_line: if line.product_id.invoice_policy == 'cost': order._create_analytic_account() break if self.env['ir.values'].get_default('sale.config.settings', 'auto_done_setting'): self.action_done() @api.multi def _create_analytic_account(self, prefix=None): for order in self: name = order.name if prefix: name = prefix + ": " + order.name analytic = self.env['account.analytic.account'].create({ 'name': name, 'code': order.client_order_ref, 'company_id': order.company_id.id, 'partner_id': order.partner_id.id }) order.project_id = analytic
class LunchOrder(models.Model): """ A lunch order contains one or more lunch order line(s). It is associated to a user for a given date. When creating a lunch order, applicable lunch alerts are displayed. """ _name = 'lunch.order' _description = 'Lunch Order' _order = 'date desc' def _default_previous_order_ids(self): prev_order = self.env['lunch.order.line'].search([('user_id', '=', self.env.uid), ('product_id.active', '!=', False)], limit=20, order='id desc') # If we return return prev_order.ids, we will have duplicates (identical orders). # Therefore, this following part removes duplicates based on product_id and note. return { (order.product_id, order.note): order.id for order in prev_order }.values() user_id = fields.Many2one('res.users', 'User', required=True, readonly=True, states={'new': [('readonly', False)]}, default=lambda self: self.env.uid) date = fields.Date('Date', required=True, readonly=True, states={'new': [('readonly', False)]}, default=fields.Date.context_today) order_line_ids = fields.One2many('lunch.order.line', 'order_id', 'Products', ondelete="cascade", readonly=True, copy=True, states={'new': [('readonly', False)], False: [('readonly', False)]}) total = fields.Float(compute='_compute_total', string="Total", store=True) state = fields.Selection([('new', 'New'), ('confirmed', 'Received'), ('cancelled', 'Cancelled')], 'Status', readonly=True, index=True, copy=False, default='new', compute='_compute_order_state', store=True) alerts = fields.Text(compute='_compute_alerts_get', string="Alerts") previous_order_ids = fields.Many2many('lunch.order.line', compute='_compute_previous_order_ids', default=lambda self: self._default_previous_order_ids()) company_id = fields.Many2one('res.company', related='user_id.company_id', store=True) currency_id = fields.Many2one('res.currency', related='company_id.currency_id', readonly=True, store=True) cash_move_balance = fields.Monetary(compute='_compute_cash_move_balance', multi='cash_move_balance') balance_visible = fields.Boolean(compute='_compute_cash_move_balance', multi='cash_move_balance') @api.one @api.depends('order_line_ids') def _compute_total(self): """ get and sum the order lines' price """ self.total = sum( orderline.price for orderline in self.order_line_ids) @api.multi def name_get(self): return [(order.id, '%s %s' % (_('Lunch Order'), '#%d' % order.id)) for order in self] @api.depends('state') def _compute_alerts_get(self): """ get the alerts to display on the order form """ alert_msg = [alert.message for alert in self.env['lunch.alert'].search([]) if alert.display] if self.state == 'new': self.alerts = alert_msg and '\n'.join(alert_msg) or False @api.depends('user_id') def _compute_previous_order_ids(self): self.previous_order_ids = self._default_previous_order_ids() @api.one @api.depends('user_id') def _compute_cash_move_balance(self): domain = [('user_id', '=', self.user_id.id)] lunch_cash = self.env['lunch.cashmove'].read_group(domain, ['amount', 'user_id'], ['user_id']) if len(lunch_cash): self.cash_move_balance = lunch_cash[0]['amount'] self.balance_visible = (self.user_id == self.env.user) or self.user_has_groups('lunch.group_lunch_manager') @api.one @api.constrains('date') def _check_date(self): """ Prevents the user to create an order in the past """ date_order = datetime.datetime.strptime(self.date, '%Y-%m-%d') date_today = datetime.datetime.strptime(fields.Date.context_today(self), '%Y-%m-%d') if (date_order < date_today): raise ValidationError(_('The date of your order is in the past.')) @api.one @api.depends('order_line_ids.state') def _compute_order_state(self): """ Update the state of lunch.order based on its orderlines. Here is the logic: - if at least one order line is cancelled, the order is set as cancelled - if no line is cancelled but at least one line is not confirmed, the order is set as new - if all lines are confirmed, the order is set as confirmed """ if not self.order_line_ids: self.state = 'new' else: isConfirmed = True for orderline in self.order_line_ids: if orderline.state == 'cancelled': self.state = 'cancelled' return elif orderline.state == 'confirmed': continue else: isConfirmed = False if isConfirmed: self.state = 'confirmed' else: self.state = 'new' return
class PurchaseRequest(models.Model): _name = 'purchase.request' _description = 'Purchase Request' _inherit = ['mail.thread', 'ir.needaction_mixin'] @api.model def _company_get(self): company_id = self.env['res.company']._company_default_get(self._name) return self.env['res.company'].browse(company_id.id) @api.model def _get_default_requested_by(self): return self.env['res.users'].browse(self.env.uid) @api.model def _get_default_name(self): return self.env['ir.sequence'].get('purchase.request') @api.model def _default_picking_type(self): type_obj = self.env['stock.picking.type'] company_id = self.env.context.get('company_id') or \ self.env.user.company_id.id types = type_obj.search([('code', '=', 'incoming'), ('warehouse_id.company_id', '=', company_id)]) if not types: types = type_obj.search([('code', '=', 'incoming'), ('warehouse_id', '=', False)]) return types[:1] @api.multi @api.depends('state') def _compute_is_editable(self): for rec in self: if rec.state in ('to_approve', 'approved', 'rejected'): rec.is_editable = False else: rec.is_editable = True @api.multi def _track_subtype(self, init_values): for rec in self: if 'state' in init_values and rec.state == 'to_approve': return 'purchase_request.mt_request_to_approve' elif 'state' in init_values and rec.state == 'to_department_manager_approved': return 'purchase_request.mt_request_to_department_manager_approved' elif 'state' in init_values and rec.state == 'to_accountant_manager_approved': return 'purchase_request.mt_request_to_accountant_manager_approved' elif 'state' in init_values and rec.state == 'approved': return 'purchase_request.mt_request_approved' elif 'state' in init_values and rec.state == 'rejected': return 'purchase_request.mt_request_rejected' return super(PurchaseRequest, self)._track_subtype(init_values) name = fields.Char('Request Reference', size=32, required=True, default=_get_default_name, track_visibility='onchange') origin = fields.Char('Source Document', size=32) date_start = fields.Date('Creation date', help="Date when the user initiated the " "request.", default=fields.Date.context_today, track_visibility='onchange') date_finish = fields.Date('Expected date', help="Date when the Request will " "Finish.", default=fields.Date.context_today, compute='_check_the_date', track_visibility='onchange') requested_by = fields.Many2one('res.users', 'Requested by', required=True, track_visibility='onchange', default=_get_default_requested_by) assigned_to = fields.Many2one('res.users', 'Department Managers', domain=[('x_department_manager', '=', True)], track_visibility='onchange') assigned_to_2 = fields.Many2one('res.users', 'Department Managers', domain=[('x_department_manager', '=', True) ], track_visibility='onchange') assigned_to_3 = fields.Many2one('res.users', 'Projects or Sections Managers', domain=[('x_project_manager', '=', True)], track_visibility='onchange') description = fields.Text('Description') direct_manager_notes = fields.Text('Direct manager notes') department_manager_notes = fields.Text('Director notes') accountant_manager_notes = fields.Text('CFO notes') executive_manager_notes = fields.Text('Executive manager notes') treasurer_manager_notes = fields.Text('Treasurer notes') president_manager_notes = fields.Text('Chairman notes') company_id = fields.Many2one('res.company', 'Company', required=True, default=_company_get, track_visibility='onchange') line_ids = fields.One2many('purchase.request.line', 'request_id', 'Products to Purchase', readonly=False, copy=True, track_visibility='onchange') state = fields.Selection(selection=_STATES, string='Status', index=True, track_visibility='onchange', required=True, copy=False, default='draft') stage = fields.Selection(selection=_STAGES, default=1, string='Stage') steps = fields.Selection(selection=_STEPS, string='Technical Specifications Steps') request_type = fields.Selection(selection=_TYPES, default=1, string='Request Type') type_reason = fields.Text('Reason') department = fields.Many2one('hr.department', 'Department', track_visibility='onchange') project = fields.Many2one('hr.department', 'Project', track_visibility='onchange') is_editable = fields.Boolean(string="Is editable", compute="_compute_is_editable", readonly=True) picking_type_id = fields.Many2one('stock.picking.type', 'Picking Type', required=True, default=_default_picking_type) ontime = fields.Integer(string='On Time', compute="change_ontime", readonly=True) ontime_stage = fields.Integer(string='On Time Stage', compute="change_ontime_stage", readonly=True) done1 = fields.Char(string='Done', compute="change_done_stage", default='early') progress = fields.Float(string='Progress', compute='change_progress', readonly=True) color = fields.Integer('Color Index', compute="change_colore_on_kanban") price_alltotal = fields.Float(string='Total Price', compute='_compute_amount_all', store=True) @api.multi @api.depends('line_ids.price_total') def _compute_amount_all(self): for request in self: for line in request.line_ids: request.price_alltotal += line.price_total if request.price_alltotal > 0: request.stage = 5 @api.multi def copy(self, default=None): default = dict(default or {}) self.ensure_one() default.update({ 'state': 'draft', 'name': self.env['ir.sequence'].get('purchase.request'), }) return super(PurchaseRequest, self).copy(default) @api.model def create(self, vals): request = super(PurchaseRequest, self).create(vals) if vals.get('assigned_to'): request.message_subscribe_users(user_ids=[request.assigned_to.id]) return request @api.multi def write(self, vals): res = super(PurchaseRequest, self).write(vals) for request in self: if vals.get('assigned_to'): self.message_subscribe_users(user_ids=[request.assigned_to.id]) return res @api.multi def button_draft(self): for rec in self: rec.state = 'draft' return True @api.multi def button_to_approve(self): for rec in self: rec.state = 'to_approve' return True @api.multi def button_to_department_manager_approved(self): for rec in self: rec.state = 'to_department_manager_approved' return True @api.multi def button_to_accountant_manager_approved(self): for rec in self: rec.state = 'to_accountant_manager_approved' rec.stage = 2 return True @api.multi def button_approved(self): for rec in self: rec.state = 'approved' rec.stage = 6 return True @api.multi def button_rejected(self): for rec in self: rec.state = 'rejected' return True @api.multi def _check_the_date(self): #for rec in self: # d1 = datetime.datetime.strptime((rec.date_start),'%Y-%m-%d') # new_date = d1 + datetime.timedelta(days=18) # rec.date_finish = new_date for rec in self: if rec.price_alltotal <= 500: d1 = datetime.datetime.strptime((rec.date_start), '%Y-%m-%d') new_date = d1 + datetime.timedelta(days=4) rec.date_finish = new_date elif rec.price_alltotal > 500 and rec.price_alltotal <= 5000: d1 = datetime.datetime.strptime((rec.date_start), '%Y-%m-%d') new_date = d1 + datetime.timedelta(days=5) rec.date_finish = new_date elif rec.price_alltotal > 5000 and rec.price_alltotal <= 100000: d1 = datetime.datetime.strptime((rec.date_start), '%Y-%m-%d') new_date = d1 + datetime.timedelta(days=7) rec.date_finish = new_date elif rec.price_alltotal > 100000: d1 = datetime.datetime.strptime((rec.date_start), '%Y-%m-%d') new_date = d1 + datetime.timedelta(days=15) rec.date_finish = new_date def change_progress(self): for rec in self: x = rec.stage y = x * 100 / 14 rec.progress = y def change_ontime(self): for rec in self: d1 = datetime.datetime.today() d2 = datetime.datetime.strptime((rec.date_finish), '%Y-%m-%d') d = str((d2 - d1).days + 1) rec.ontime = d def change_ontime_stage(self): for rec in self: d1 = datetime.datetime.today() d2 = datetime.datetime.strptime((rec.date_start), '%Y-%m-%d') d = str((d1 - d2).days + 1) rec.ontime_stage = d def change_done_stage(self): for rec in self: if rec.price_alltotal <= 500: if rec.stage == 1 and rec.ontime_stage > 1: dd = "late" rec.done1 = dd elif rec.stage == 2 and rec.ontime_stage > 2: dd = "late" rec.done1 = dd elif rec.stage == 3 and rec.ontime_stage > 4: dd = "late" rec.done1 = dd elif rec.stage == 4 and rec.ontime_stage > 4: dd = "late" rec.done1 = dd elif rec.stage == 5 and rec.ontime_stage > 4: dd = "late" rec.done1 = dd elif rec.stage == 6 and rec.ontime_stage > 4: dd = "late" rec.done1 = dd elif rec.price_alltotal > 500 and rec.price_alltotal <= 5000: if rec.stage == 1 and rec.ontime_stage > 1: dd = "late" rec.done1 = dd elif rec.stage == 2 and rec.ontime_stage > 2: dd = "late" rec.done1 = dd elif rec.stage == 3 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 4 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 5 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 6 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.price_alltotal > 5000 and rec.price_alltotal <= 100000: if rec.stage == 1 and rec.ontime_stage > 1: dd = "late" rec.done1 = dd elif rec.stage == 2 and rec.ontime_stage > 2: dd = "late" rec.done1 = dd elif rec.stage == 3 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 4 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 5 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.stage == 6 and rec.ontime_stage > 5: dd = "late" rec.done1 = dd elif rec.price_alltotal > 100000: if rec.stage == 1 and rec.ontime_stage > 1: dd = "late" rec.done1 = dd elif rec.stage == 2 and rec.ontime_stage > 2: dd = "late" rec.done1 = dd elif rec.stage == 3 and rec.ontime_stage > 7: dd = "late" rec.done1 = dd elif rec.stage == 4 and rec.ontime_stage > 7: dd = "late" rec.done1 = dd elif rec.stage == 5 and rec.ontime_stage > 7: dd = "late" rec.done1 = dd elif rec.stage == 6 and rec.ontime_stage > 7: dd = "late" rec.done1 = dd elif (rec.stage == 7 or rec.stage == 8 or rec.stage == 9 or rec.stage == 10) and rec.ontime_stage > 15: dd = "late" rec.done1 = dd elif (rec.stage == 11 or rec.stage == 12 or rec.stage == 13) and rec.ontime_stage > 12: dd = "late" rec.done1 = dd def change_colore_on_kanban(self): for record in self: color = 0 if record.ontime < 0: color = 2 elif record.ontime == 0: color = 3 elif record.ontime > 0: color = 5 record.color = color
class is_cout(models.Model): _name='is.cout' _order='name' _sql_constraints = [('name_uniq', 'unique(name)', u"Ce code existe déja !")] name = fields.Many2one('product.product', 'Article', required=True, readonly=False, select=True) code_pg = fields.Char('Code PG' , related='name.product_tmpl_id.is_code', readonly=True) designation = fields.Char('Désignation', related='name.product_tmpl_id.name' , readonly=True) cout_calcul_id = fields.Many2one('is.cout.calcul', 'Calcul des coût') is_category_id = fields.Many2one('is.category', 'Catégorie') is_gestionnaire_id = fields.Many2one('is.gestionnaire', 'Gestionnaire') is_mold_id = fields.Many2one('is.mold', 'Moule') is_mold_dossierf = fields.Char('Moule ou Dossier F') partner_id = fields.Many2one('res.partner', 'Client par défaut') type_article = fields.Selection([('A', u'Acheté'),('F', u'Fabriqué'),('ST', u'Sous-traité')], "Type d'article") uom_id = fields.Many2one('product.uom', 'Unité') lot_mini = fields.Float("Lot d'appro.") prix_tarif = fields.Float("Prix tarif" , digits=(12, 4)) prix_commande = fields.Float("Prix dernière commande" , digits=(12, 4)) prix_facture = fields.Float("Prix dernière facture" , digits=(12, 4)) prix_force = fields.Float("Prix forcé (saisie manuelle)", digits=(12, 4)) prix_force_commentaire = fields.Char("Commentaire") prix_calcule = fields.Float("Prix calculé" , digits=(12, 4)) prix_sous_traitance = fields.Float("Prix sous-traitance" , digits=(12, 4)) ecart_calcule_matiere = fields.Float("Ecart Calculé/Matière" , digits=(12, 4)) cout_act_matiere = fields.Float("Coût act matière" , digits=(12, 4)) cout_act_condition = fields.Float("Coût act conditionnement", digits=(12, 4)) cout_act_machine = fields.Float("Coût act machine" , digits=(12, 4)) cout_act_mo = fields.Float("Coût act main d'oeuvre" , digits=(12, 4)) cout_act_machine_pk = fields.Float("Coût act machine PK" , digits=(12, 4)) cout_act_mo_pk = fields.Float("Coût act main d'oeuvre PK", digits=(12, 4)) cout_act_st = fields.Float("Coût act sous-traitance" , digits=(12, 4)) cout_act_total = fields.Float("Coût act Total" , digits=(12, 4)) cout_act_prix_vente = fields.Float("Prix de vente actualisé" , digits=(12, 4)) cout_std_matiere = fields.Float("Coût std matière" , digits=(12, 4)) cout_std_condition = fields.Float("Coût std conditionnement" , digits=(12, 4)) cout_std_machine = fields.Float("Coût std machine" , digits=(12, 4)) cout_std_mo = fields.Float("Coût std main d'oeuvre" , digits=(12, 4)) cout_std_st = fields.Float("Coût std sous-traitance" , digits=(12, 4)) cout_std_total = fields.Float("Coût std Total" , digits=(12, 4)) cout_std_prix_vente = fields.Float("Prix de vente standard" , digits=(12, 4)) cout_budget_matiere = fields.Float("Coût budget matière" , digits=(12, 4)) cout_budget_condition = fields.Float("Coût budget conditionnement" , digits=(12, 4)) cout_budget_machine = fields.Float("Coût budget machine" , digits=(12, 4)) cout_budget_mo = fields.Float("Coût budget main d'oeuvre" , digits=(12, 4)) cout_budget_st = fields.Float("Coût budget sous-traitance" , digits=(12, 4)) cout_budget_total = fields.Float("Coût budget Total" , digits=(12, 4)) cout_budget_prix_vente = fields.Float("Prix de vente budget" , digits=(12, 4)) amortissement_moule = fields.Float("Amortissement Moule" , digits=(12, 4), compute='_compute') surcout_pre_serie = fields.Float("Surcôut pré-série" , digits=(12, 4), compute='_compute') prix_vente = fields.Float("Prix de Vente" , digits=(12, 4), compute='_compute') nomenclature_ids = fields.One2many('is.cout.nomenclature', 'cout_id', u"Lignes de la nomenclature") gamme_ma_ids = fields.One2many('is.cout.gamme.ma' , 'cout_id', u"Lignes gamme machine") gamme_mo_ids = fields.One2many('is.cout.gamme.mo' , 'cout_id', u"Lignes gamme MO") gamme_ma_pk_ids = fields.One2many('is.cout.gamme.ma.pk' , 'cout_id', u"Lignes gamme machine PK") gamme_mo_pk_ids = fields.One2many('is.cout.gamme.mo.pk' , 'cout_id', u"Lignes gamme MO PK") niveau = fields.Integer('Niveau le plus bas dans la nomenclature') nb_err = fields.Integer('Nb Err', help=u"Nombre d'erreures détectées lors du calcul de coûts") @api.depends('name') def _compute(self): for obj in self: #** Recherche du tarif commercial pour le client par défaut ******** code_client=mem_code_client=False for client in obj.name.product_tmpl_id.is_client_ids: mem_code_client=client.client_id.is_code if client.client_defaut: code_client=mem_code_client if code_client==False: code_client=mem_code_client tarifs=self.env['is.tarif.cial'].search([ ('product_id', '=', obj.name.product_tmpl_id.id), ('indice_prix', '=', 999), ('partner_id.is_code', '=', code_client) ]) for tarif in tarifs: obj.amortissement_moule = tarif.amortissement_moule obj.surcout_pre_serie = tarif.surcout_pre_serie obj.prix_vente = tarif.prix_vente @api.multi def write(self, vals): for obj in self: matiere = vals.get('cout_std_matiere' , obj.cout_std_matiere) machine = vals.get('cout_std_machine' , obj.cout_std_machine) mo = vals.get('cout_std_mo' , obj.cout_std_mo) st = vals.get('cout_std_st' , obj.cout_std_st) vals['cout_std_total']=matiere+machine+mo+st res=super(is_cout, self).write(vals) return res @api.multi def action_calcul_cout(self): for obj in self: vals={ 'product_id' : obj.name.id, 'multiniveaux' : False, } cout_calcul=self.env['is.cout.calcul'].create(vals) cout_calcul.action_calcul_prix_achat_thread(nb_threads=0) cout_calcul.action_calcul_prix_revient() return { 'name': obj.name.name, 'view_mode': 'form', 'view_type': 'form', 'res_model': 'is.cout', 'type': 'ir.actions.act_window', 'res_id': obj.id, } @api.multi def action_calcul_cout_pk(self): for obj in self: vals={ 'product_id' : obj.name.id, 'multiniveaux' : False, } cout_calcul=self.env['is.cout.calcul'].create(vals) cout_calcul.action_calcul_prix_achat_thread(nb_threads=0) cout_calcul.action_calcul_prix_revient() dummy, view_id = self.env['ir.model.data'].get_object_reference('is_plastigray', 'is_cout_pk_form_view') return { 'name': obj.name.name, 'view_mode': 'form', 'view_type': 'form', 'res_model': 'is.cout', 'type': 'ir.actions.act_window', 'view_id': view_id, 'res_id': obj.id, } @api.multi def _copie_cout_actualise_dans_cout_standard(self,obj): vals={ 'cout_std_matiere' : obj.cout_act_matiere, 'cout_std_condition' : obj.cout_act_condition, 'cout_std_machine' : obj.cout_act_machine, 'cout_std_mo' : obj.cout_act_mo, 'cout_std_st' : obj.cout_act_st, 'cout_std_total' : obj.cout_act_total, 'cout_std_prix_vente' : obj.cout_act_prix_vente, } obj.write(vals) @api.multi def copie_cout_actualise_dans_cout_standard(self): for obj in self: self._copie_cout_actualise_dans_cout_standard(obj) @api.multi def _copie_cout_actualise_dans_cout_budget(self,obj): vals={ 'cout_budget_matiere' : obj.cout_act_matiere, 'cout_budget_condition' : obj.cout_act_condition, 'cout_budget_machine' : obj.cout_act_machine, 'cout_budget_mo' : obj.cout_act_mo, 'cout_budget_st' : obj.cout_act_st, 'cout_budget_total' : obj.cout_act_total, 'cout_budget_prix_vente' : obj.cout_act_prix_vente, } obj.write(vals) @api.multi def copie_cout_actualise_dans_cout_budget(self): for obj in self: self._copie_cout_actualise_dans_cout_budget(obj) @api.multi def initialisation_prix_vente_standard(self): for obj in self: obj.cout_std_prix_vente = obj.prix_vente-obj.amortissement_moule-obj.surcout_pre_serie @api.model def print_btn_report(self): threaded_calculation = threading.Thread(target=self.save_cout_report, args=()) threaded_calculation.start() return True def save_cout_report(self): user = self.env['res.users'].browse(self._uid) with api.Environment.manage(): new_cr = self.pool.cursor() self = self.with_env(self.env(cr=new_cr)) report_service = 'is_plastigray.report_is_cout' #file_param = self.env['ir.config_parameter'].get_param('path_report_pdf') db=self._cr.dbname path="/tmp/couts-" + db cde="rm -Rf " + path os.popen(cde).readlines() if not os.path.exists(path): os.makedirs(path) recs=self.search([], order="name",limit=50000) nb=len(recs) _logger.info("#### Début sauvegarde Coûts ####") ct=0 for rec in recs: ct=ct+1 code_pg=rec.name.is_code _logger.info('- '+str(ct)+'/'+str(nb)+' : '+str(code_pg)) result, format = self.env['report'].get_pdf(rec, report_service), 'pdf' file_name = path + '/'+str(code_pg) +'.pdf' fd = os.open(file_name,os.O_RDWR|os.O_CREAT) try: os.write(fd, result) finally: os.close(fd) filename="/var/www/odoo/couts/"+db+".zip" cde="rm -f " + filename + " && cd /tmp && zip -r " + filename + " couts-" +db+" && chmod 755 "+filename os.popen(cde).readlines() self.send_mail_notyfy_user() new_cr.close() _logger.info("#### Fin sauvegarde Coûts ####") return {} def send_mail_notyfy_user(self): db=self._cr.dbname user = self.env['res.users'].browse(self._uid) mail_pool = self.env['mail.mail'] values={} values.update({'subject': 'Génération des PDF des coûts terminée'}) values.update({'email_from': user.partner_id.email}) values.update({'email_to': user.partner_id.email}) values.update({'body_html': '<p>Bonjour,</p><p>Le zip contenant tous les PDF est disponible <a href="http://odoo/couts/'+db+'.zip">ici</a></p>' }) #values.update({'body': 'Bonjour,\nLe zip contenant tous les PDF est disonible ici http://odoo/couts-odoo1.zip' }) # values.update({'res_id': 'obj.id' }) #[optional] here is the record id, where you want to post that email after sending values.update({'model': 'is.cout' }) #[optional] here is the object(like 'project.project') to whose record id you want to post that email after sending msg_id = mail_pool.sudo().create(values) # And then call send function of the mail.mail, if msg_id: msg_id.send() return True @api.multi def cout_standard_indice_precedent(self): if len(self)>1: raise Warning(u"Modification multiple non autorisée !") for obj in self: is_code=obj.name.is_code indice=is_code[6:7] if indice=='': raise Warning(u"Code sans indice !") code=is_code[0:6] if indice!='A': code=code+chr(ord(indice)-1) couts=self.env['is.cout'].search([('name.is_code', '=', code)]) if len(couts)==0: raise Warning(u"Coût précédent non trouvé !") for cout in couts: obj.cout_std_matiere = cout.cout_std_matiere obj.cout_std_condition = cout.cout_std_condition obj.cout_std_machine = cout.cout_std_machine obj.cout_std_mo = cout.cout_std_mo obj.cout_std_st = cout.cout_std_st obj.cout_std_total = cout.cout_std_total obj.cout_std_prix_vente = cout.cout_std_prix_vente
class PurchaseRequestLine(models.Model): _name = "purchase.request.line" _description = "Purchase Request Line" _inherit = ['mail.thread', 'ir.needaction_mixin'] @api.multi @api.depends('product_id', 'name', 'product_uom_id', 'product_qty', 'analytic_account_id', 'date_required', 'specifications') def _compute_is_editable(self): for rec in self: if rec.request_id.state in ('to_approve', 'approved', 'rejected'): rec.is_editable = False else: rec.is_editable = True @api.multi def _compute_supplier_id(self): for rec in self: if rec.product_id: if rec.product_id.seller_ids: rec.supplier_id = rec.product_id.seller_ids[0].name product_id = fields.Many2one('product.product', 'Product', domain=[('purchase_ok', '=', True)], track_visibility='onchange') name = fields.Char('Description', size=256, track_visibility='onchange') product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure', track_visibility='onchange') product_qty = fields.Float( 'Quantity', track_visibility='onchange', digits_compute=dp.get_precision('Product Unit of Measure')) product_price = fields.Float('Price', track_visibility='onchange') accepted = fields.Boolean('Accepted', track_visibility='onchange') request_id = fields.Many2one('purchase.request', 'Purchase Request', ondelete='cascade', readonly=True) company_id = fields.Many2one('res.company', related='request_id.company_id', string='Company', store=True, readonly=True) analytic_account_id = fields.Many2one('account.analytic.account', 'Analytic Account', track_visibility='onchange') requested_by = fields.Many2one('res.users', related='request_id.requested_by', string='Requested by', store=True, readonly=True) assigned_to = fields.Many2one('res.users', related='request_id.assigned_to', string='Assigned to', store=True, readonly=True) date_start = fields.Date(related='request_id.date_start', string='Request Date', readonly=True, store=True) description = fields.Text(related='request_id.description', string='Description', readonly=True, store=True) origin = fields.Char(related='request_id.origin', size=32, string='Source Document', readonly=True, store=True) date_required = fields.Date(string='Request Date', required=True, track_visibility='onchange', default=fields.Date.context_today) is_editable = fields.Boolean(string='Is editable', compute="_compute_is_editable", readonly=True) specifications = fields.Text(string='Specifications') request_state = fields.Selection(string='Request state', readonly=True, related='request_id.state', selection=_STATES, store=True) supplier_id = fields.Many2one('res.partner', string='Preferred supplier', compute="_compute_supplier_id") procurement_id = fields.Many2one('procurement.order', 'Procurement Order', readonly=True) attachment_ids = fields.Many2many('ir.attachment', 'class_ir_attachments_rel', 'class_id', 'attachment_id', 'Attachments') price_total = fields.Float(string='Total', track_visibility='onchange', compute="_compute_amount", store=True) @api.onchange('product_id') def onchange_product_id(self): if self.product_id: name = self.product_id.name if self.product_id.code: name = '[%s] %s' % (name, self.product_id.code) if self.product_id.description_purchase: name += '\n' + self.product_id.description_purchase self.product_uom_id = self.product_id.uom_id.id self.product_qty = 1 self.name = name @api.multi @api.depends('product_qty', 'product_price') def _compute_amount(self): if self.product_qty > 0: self.price_total = self.product_price * self.product_qty
class res_partner(models.Model): _inherit = 'res.partner' # F#13145 In the tree view of partner, # replace the column Phone by "Phone/Mobile" @api.multi def _get_full_phone(self): for record in self: full_phone = [] if record.phone: full_phone.append(record.phone) if record.mobile: full_phone.append(record.mobile) record.phone_mobile = " / ".join(full_phone) if full_phone else '' @api.depends('is_company') def _get_title_domain(self): """ Use for the domain on field Title: - NOT Is Company: titles with type `contact` - Is Company: titles with type `partner` """ for record in self: if record.is_company: record.title_domain = 'partner' else: record.title_domain = 'contact' phone_mobile = fields.Char(compute='_get_full_phone', string='Phone/Mobile') event_ids = fields.One2many(comodel_name='trobz.crm.event', inverse_name='partner_id', string='Events') lead_ids = fields.One2many(comodel_name='crm.lead', inverse_name='partner_id', string='Leads') skype_contact = fields.Char('Skype Contact', size=64) linkedin_profile = fields.Char('Linkedin Profile', size=64) create_uid = fields.Many2one(comodel_name='res.users', string='Creator') create_date = fields.Datetime('Creation Date') prospect = fields.Boolean( 'Prospect', help="Check this box if this contact is a prospect.") business_sector_id = fields.Many2one( comodel_name='trobz.crm.business.sector', string='Business Sector') title_domain = fields.Selection([('contact', 'Contact'), ('partner', 'Partner')], 'Title Domain', compute='_get_title_domain', store=True) @api.onchange('customer') def check_cutomer(self): if self.customer: self.prospect = False @api.onchange('prospect') def check_prospect(self): if self.prospect: self.customer = False @api.onchange('parent_id') def onchange_parent_id(self): if self.parent_id: self.customer = self.parent_id.customer self.prospect = self.parent_id.prospect self.supplier = self.parent_id.supplier # Can not migrate this function because onchange_state is called from Odoo def onchange_state(self, cr, uid, ids, state_id, context=None): if state_id: country_id = self.pool.get('res.country.state').browse( cr, uid, state_id, context).country_id.id return {'value': {'country_id': country_id}} return {} @api.model def default_get(self, fields): ctx = self._context and self._context.copy() or {} res = super(res_partner, self).default_get(fields) res.update({ 'is_company': False, }) # F#12640 : Update Related User and company for Partner.contact # Get customer/prospect/supplier like company if ctx.get('default_parent_id', False): parent_obj = self.browse(ctx['default_parent_id']) res.update({ 'customer': parent_obj.customer, 'prospect': parent_obj.prospect, 'supplier': parent_obj.supplier, 'use_parent_address': True, }) return res @api.multi def write(self, vals): context = self._context and self._context.copy() or {} context.update({'from_partner': 1}) res = super(res_partner, self).write(vals) # F#12640: For partner set as is_company, when updating the fields # ‘Customer/Supplier/Prospect’, automatically set the same value # on the contacts of that company. child_new_vals = {} if 'customer' in vals: child_new_vals['customer'] = vals.get('customer', False) if 'prospect' in vals: child_new_vals['prospect'] = vals.get('prospect', False) if 'supplier' in vals: child_new_vals['supplier'] = vals.get('supplier', False) if child_new_vals: for parent_obj in self: if parent_obj.is_company and parent_obj.child_ids: parent_obj.child_ids.write(child_new_vals) return res @api.multi def name_get(self): context = self._context or {} if not self: return [] res = [] for r in self: if context.get('contact_display', 'contact') == 'partner' and \ r.parent_id: res.append((r.id, r.parent_id.id)) else: res.append((r.id, r.name or '/')) return res @api.model def name_search(self, name='', args=None, operator='ilike', limit=100): if not args: args = [] context = dict(self._context) if 'crm_partner_id' in context: crm_partner_id = context.get('crm_partner_id', False) if not crm_partner_id: args = [('id', 'in', [])] else: partners = self.env['res.partner'].search([('id', '=', crm_partner_id)]) if partners: partner = partners[0] contact_ids = [contact.id for contact in partner.child_ids] args = [('id', 'in', contact_ids)] return super(res_partner, self).name_search(name=name, args=args, operator=operator, limit=limit)
class Task(models.Model): _name = "hc.res.task" _description = "Task" identifier_id = fields.One2many(comodel_name="hc.task.identifier", inverse_name="task_id", string="Identifier", help="Task Instance Identifier.") definition_type = fields.Selection( string="Defintion Type", selection=[("uri", "URI"), ("activity_definition", "Activity Definition")], help="Type of formal definition of task.") definition_name = fields.Char(string="Definition", help="Formal definition of task.") definition_uri = fields.Char(string="Definition URI", help="URI of formal definition of task.") definition_activity_definition_id = fields.Many2one( comodel_name="hc.res.activity.definition", string="Definition Activity Definition", help="Activity Definition formal definition of task.") based_on_ids = fields.One2many(comodel_name="hc.task.based.on", inverse_name="task_id", string="Based Ons", help="Request fulfilled by this request.") group_identifier_id = fields.Many2one( comodel_name="hc.task.group.identifier", string="Group Identifier", help="Identifier of requisition or grouper id.") part_of_ids = fields.One2many(comodel_name="hc.task.part.of", inverse_name="task_id", string="Part Of", help="Identifier of composite task.") status = fields.Selection(string="Task Status", required="True", selection=[("draft", "Draft"), ("requested", "Requested"), ("received", "Received"), ("accepted", "Accepted")], help="The current status of the task.") status_history_ids = fields.One2many( comodel_name="hc.task.status.history", inverse_name="task_id", string="Status History", help="The status of the task over time.") status_reason_id = fields.Many2one(comodel_name="hc.vs.task.status.reason", string="Status Reason", help="Reason for current status.") business_status_id = fields.Many2one( comodel_name="hc.vs.task.business.status", string="Business Status", help='E.g. "Specimen collected", "IV prepped".') intent = fields.Selection( string="Intent", required="True", selection=[("proposal", "Proposal"), ("plan", "Plan"), ("order", "Order")], help= 'Indicates the "level" of actionability associated with the Task. I.e. Is this a proposed task, a planned task, an actionable task, etc.' ) priority = fields.Selection( string="Priority", selection=[("normal", "Normal"), ("urgent", "Urgent"), ("asap", "Asap"), ("stat", "Stat")], help= "Indicates how quickly the Task should be addressed with respect to other requests." ) code_id = fields.Many2one( comodel_name="hc.vs.task.type", string="Code", help= "A name or code (or both) briefly describing what the task involves..") description = fields.Text(string="Description", help="Human-readable explanation of task.") focus_id = fields.Many2one(comodel_name="hc.task.focus", string="Focus", help="What task is acting on.") for_id = fields.Many2one(comodel_name="hc.task.for", string="For", help="Beneficiary of the Task.") context_type = fields.Selection(string="Context Type", selection=[("encounter", "Encounter"), ("episode_of_care", "Episode Of Care")], help="Type of supplemental instruction.") context_name = fields.Char( string="Context", compute="_compute_context_name", store="True", help="Healthcare event during which this task originated.") context_encounter_id = fields.Many2one( comodel_name="hc.res.encounter", string="Context Encounter", help="Encounter healthcare event during which this task originated.") context_episode_of_care_id = fields.Many2one( comodel_name="hc.res.episode.of.care", string="Context Episode Of Care", help= "Episode Of Care healthcare event during which this task originated.") execution_period_start_date = fields.Datetime( string="Execution Period Start Date", help="Start of execution.") execution_period_end_date = fields.Datetime( string="Execution Period End Date", help="End of execution.") authored_on = fields.Datetime(string="Authored On", help="Task Creation Date.") last_modified = fields.Datetime(string="Last Modified", required="True", help="Task Last Modified Date.") performer_type_ids = fields.Many2many( comodel_name="hc.vs.task.performer.type", string="Performer Types", help="The type of participant that can execute the task.") owner_type = fields.Selection(string="Owner Type", selection=[("device", "Device"), ("organization", "Organization"), ("patient", "Patient"), ("practitioner", "Practitioner"), ("related_person", "Related Person")], help="Type of task owner.") owner_name = fields.Char(string="Owner", compute="_compute_owner_name", store="True", help="Task Owner.") owner_device_id = fields.Many2one(comodel_name="hc.res.device", string="Owner Device", help="Device responsible individual.") owner_organization_id = fields.Many2one( comodel_name="hc.res.organization", string="Owner Organization", help="Organization responsible individual.") owner_patient_id = fields.Many2one(comodel_name="hc.res.patient", string="Owner Patient", help="Patient responsible individual.") owner_practitioner_id = fields.Many2one( comodel_name="hc.res.practitioner", string="Owner Practitioner", help="Practitioner responsible individual.") owner_related_person_id = fields.Many2one( comodel_name="hc.res.related.person", string="Owner Related Person", help="Related Person responsible individual.") reason_id = fields.Many2one(comodel_name="hc.vs.task.reason", string="Reason", help="Why task is needed.") note_ids = fields.One2many(comodel_name="hc.task.note", inverse_name="task_id", string="Notes", help="Comments made about the task.") relevant_history_ids = fields.One2many( comodel_name="hc.task.relevant.history", inverse_name="task_id", string="Relevant Histories", help="Identifier of key events in history of the task.") requester_id = fields.Many2one(comodel_name="hc.task.requester", string="Requester", help="Who is asking for task to be done.") restriction_id = fields.Many2one(comodel_name="hc.task.restriction", string="Restriction", help="Constraints on fulfillment tasks.") input_ids = fields.One2many(comodel_name="hc.task.input", inverse_name="task_id", string="Inputs", help="Task Input.") output_ids = fields.One2many(comodel_name="hc.task.output", inverse_name="task_id", string="Outputs", help="Task Output.") @api.model def create(self, vals): business_status_history_obj = self.env[ 'hc.task.business.status.history'] status_history_obj = self.env['hc.task.status.history'] res = super(Condition, self).create(vals) # For Status if vals and vals.get('status'): status_history_vals = { 'task_id': res.id, 'status': res.status, 'start_date': datetime.today() } if vals.get('status') == 'entered-in-error': status_history_vals.update({'end_date': datetime.today()}) status_history_obj.create(status_history_vals) # For Business Status if vals.get('status') != 'entered-in-error': if vals and vals.get('business_status_id'): business_status_history_vals = { 'task_id': res.id, 'business_status_id': res.business_status_id, 'start_date': datetime.today() } business_status_history_obj.create( business_status_history_vals) return res @api.multi def write(self, vals): business_status_history_obj = self.env[ 'hc.task.business.status.history'] status_history_obj = self.env['hc.task.status.history'] res = super(Condition, self).write(vals) # For Status status_history_record_ids = status_history_obj.search([('end_date', '=', False)]) if status_history_record_ids: if vals.get('status') and status_history_record_ids[ 0].status != vals.get('status'): for status_history in status_history_record_ids: status_history.end_date = datetime.strftime( datetime.today(), DTF) time_diff = datetime.today() - datetime.strptime( status_history.start_date, DTF) if time_diff: days = str(time_diff).split(',') if days and len(days) > 1: status_history.time_diff_day = str(days[0]) times = str(days[1]).split(':') if times and times > 1: status_history.time_diff_hour = str(times[0]) status_history.time_diff_min = str(times[1]) status_history.time_diff_sec = str(times[2]) else: times = str(time_diff).split(':') if times and times > 1: status_history.time_diff_hour = str(times[0]) status_history.time_diff_min = str(times[1]) status_history.time_diff_sec = str(times[2]) status_history_vals = { 'task_id': self.id, 'status': vals.get('status'), 'start_date': datetime.today() } if vals.get('status') == 'entered-in-error': status_history_vals.update({'end_date': datetime.today()}) status_history_obj.create(status_history_vals) # For Clinical Status business_status_history_record_ids = business_status_history_obj.search( [('end_date', '=', False)]) if business_status_history_record_ids: if vals.get('status') == 'entered-in-error' or ( vals.get('business_status_id') and business_status_history_record_ids[0].business_status_id != vals.get('business_status_id')): for business_status_history in business_status_history_record_ids: business_status_history.end_date = datetime.strftime( datetime.today(), DTF) time_diff = datetime.today() - datetime.strptime( business_status_history.start_date, DTF) if time_diff: days = str(time_diff).split(',') if days and len(days) > 1: business_status_history.time_diff_day = str( days[0]) times = str(days[1]).split(':') if times and times > 1: business_status_history.time_diff_hour = str( times[0]) business_status_history.time_diff_min = str( times[1]) business_status_history.time_diff_sec = str( times[2]) else: times = str(time_diff).split(':') if times and times > 1: business_status_history.time_diff_hour = str( times[0]) business_status_history.time_diff_min = str( times[1]) business_status_history.time_diff_sec = str( times[2]) business_status_history_vals = { 'task_id': self.id, 'business_status_id': vals.get('business_status_id'), 'start_date': datetime.today() } if vals.get('status') == 'entered-in-error': business_status_history_vals.update( {'end_date': datetime.today()}) if vals.get('status') != 'entered-in-error': business_status_history_obj.create( business_status_history_vals) else: business_status_history_vals = { 'task_id': self.id, 'business_status_id': vals.get('business_status_id'), 'start_date': datetime.today() } if vals.get('status') == 'entered-in-error': business_status_history_vals.update( {'end_date': datetime.today()}) business_status_history_obj.create(business_status_history_vals) return res
class banking_export_ch_dd(models.Model): ''' Swiss Direct Debit export containing the file created by the appropriate wizard ''' _name = 'banking.export.ch.dd' _rec_name = 'filename' def _generate_filename(self): self.ensure_one() ref = self.env['ir.sequence'].next_by_code( 'l10n.banking.export.filename') username = self.env.user.name initials = ''.join([subname[0] for subname in username.split()]) if self.type == 'LSV': res = 'lsv_%s_%s.lsv' % (ref, initials) else: res = 'dd_%s_%s.dd' % (ref, initials) self.filename = res return True @api.model def create(self, vals): res = super(banking_export_ch_dd, self).create(vals) res._generate_filename() return res payment_order_ids = fields.Many2many( 'payment.order', 'account_payment_order_ch_dd_rel', 'banking_export_ch_dd_id', 'account_order_id', _('Payment Orders'), readonly=True ) nb_transactions = fields.Integer( _('Number of Transactions'), readonly=True ) total_amount = fields.Float( _('Total Amount'), readonly=True, digits_compute=dp.get_precision('Account') ) create_date = fields.Datetime( _('Generation Date'), readonly=True ) file = fields.Binary( _('Generated file'), readonly=True ) filename = fields.Char( string=_('Filename'), size=256, readonly=True, ) state = fields.Selection( [('draft', _('Draft')), ('sent', _('Sent'))], 'State', readonly=True, default='draft' ) type = fields.Char( _('Type'), size=128, readonly=True )
class ProjectTask(models.Model): _inherit = 'project.task' state = fields.Selection(related='stage_id.state', store=True, readonly=True)
class ResPartner(models.Model): _inherit = "res.partner" discount_computation = fields.Selection( selection=[('total', 'Total'), ('unit_price', 'Unit Price')], string="Discount Computation")
class DonationLine(models.Model): _name = 'donation.line' _description = 'Donation Lines' _rec_name = 'product_id' @api.onchange('donation_id.donation_method') def onchange_donation_method(self): res = {} res['domain'] = { 'product_id': [('donation_method', '=', donation_id.donation_method.id)] } return res @api.multi @api.depends('unit_price', 'quantity', 'donation_id.currency_id', 'donation_id.donation_date', 'donation_id.company_id') def _compute_amount_company_currency(self): for line in self: amount = line.quantity * line.unit_price line.amount = amount donation_currency = line.donation_id.currency_id.with_context( date=line.donation_id.donation_date) line.amount_company_currency = donation_currency.compute( amount, line.donation_id.company_id.currency_id) donation_id = fields.Many2one('donation.donation', string='Donation', ondelete='cascade') recipt_number = fields.Char(string='Recipt Number', size=32) state = fields.Selection([ (1, 'Draft'), (2, 'Transfer'), (3, 'Done'), (4, 'Cancelled'), ], string='State', related='donation_id.state', readonly=True, copy=False, default=1, index=True, track_visibility='onchange') currency_id = fields.Many2one('res.currency', related='donation_id.currency_id', readonly=True) company_currency_id = fields.Many2one( 'res.currency', related='donation_id.company_id.currency_id', readonly=True) product_id = fields.Many2one('product.product', related='donation_id.product_id', readonly=True, store=True, string='Product', ondelete='restrict') gov_id = fields.Many2one('govs.villages.gov', related='donation_id.gov_id', readonly=True, store=True, string='Gov', ondelete='restrict') donation_date = fields.Date(related='donation_id.donation_date', readonly=True, store=True, string='Date') donation_place = fields.Many2one('donation.place', related='donation_id.donation_place', readonly=True, store=True, string='Place') partner_id = fields.Many2one('res.partner', string='Donor', required=True, index=True, track_visibility='onchange', ondelete='restrict') donation_by = fields.Many2one('res.users', string='Donation by', related='donation_id.donation_by', readonly=True, store=True) donation_collector = fields.Many2one('res.partner', string='Collector', track_visibility='onchange') quantity = fields.Integer(string='Quantity', default=1) unit_price = fields.Monetary(string='Unit Price', digits=dp.get_precision('Account'), currency_field='currency_id') amount = fields.Monetary(compute='_compute_amount_company_currency', string='Amount', currency_field='currency_id', digits=dp.get_precision('Account'), store=True) amount_company_currency = fields.Monetary( compute='_compute_amount_company_currency', string='Amount in Company Currency', currency_field='company_currency_id', digits=dp.get_precision('Account'), store=True) campaign_id = fields.Many2one( 'donation.campaign', string='Donation Campaign', track_visibility='onchange', ondelete='restrict', default=lambda self: self.env.user.context_donation_campaign_id) analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', domain=[('account_type', '!=', 'closed')], ondelete='restrict') #campaign_id = fields.Many2one( analytic_account2 = fields.Many2one( 'account.analytic.account', related='campaign_id.analytic_account_id', string='Analytic Account', readonly=True, store=True) account_id = fields.Many2one( 'account.account', related='donation_id.donation_place.account_id', string='Account', readonly=True, store=True) #analytic2 = fields.Integer(string = 'id', compute='get_analytic_account_id_3',store=True) #analytic3 = fields.Integer(string = 'id2',related='analytic_account_id.id' ,store=True) sequence = fields.Integer('Sequence') # for the fields tax_receipt_ok and in_kind, we made an important change # between v8 and v9: in v8, it was a reglar field set by an onchange # in v9, it is a related stored field tax_receipt_ok = fields.Boolean(related='product_id.tax_receipt_ok', readonly=True, store=True) donation_method = fields.Many2one(related='donation_id.donation_method', readonly=True, store=True, string='Method') in_kind = fields.Boolean(related='product_id.in_kind_donation', readonly=True, store=True, string='In Kind') tags_id = fields.Many2many('account.analytic.tag', string='Tags', readonly=True) @api.onchange('donation_id.product_id') def product_id_change(self): if donation_id.product_id: # We should change that one day... if donation_id.product_id.list_price: self.unit_price = donation_id.product_id.list_price #self.env.cr.execute("INSERT INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id)VALUES ('%s', '%d')" %(self.id,)) #@api.one #@api.depends('analytic_account_id', 'analytic_account2') #@api.model #def get_analytic_account_id_3(self): #for rec in self: #rec.env.cr.execute("SELECT method.tag_id FROM donation_line inner join donation_instrument as method on donation_line.donation_method = method.id where donation_line.id= '%s'" %(rec.id)) #res = rec.env.cr.fetchone()[0] #rec.env.cr.execute("insert INTO account_analytic_tag_donation_line_rel(donation_line_id, account_analytic_tag_id) VALUES ('%s','%s')" %(rec.id,res))11 #rec.analytic_tag = 1 #@api.one #@api.depends('analytic_account2') #@api.model #def get_analytic_account_id_2(self): #self.analytic2 = self.analytic_account_id.id # return self.analytic_account2.id or False #return self.analytic_account_id.id or False @api.model def get_analytic_account_id(self): #self.analytic2 = self.analytic_account_id.id return self.analytic_account2.id or False #return self.analytic_account_id.id or False @api.model def get_account_id(self): #self.analytic2 = self.analytic_account_id.id return self.account_id.id or False
class AccountMove(models.Model): _inherit = 'account.move' document = fields.Char( string='Document', compute='_compute_document', store=True, readonly=True, ) document_id = fields.Reference( REFERENCE_SELECT, string='Document', compute='_compute_document', store=True, readonly=True, ) doctype = fields.Selection( DOCTYPE_SELECT, string='Doctype', compute='_compute_document', store=True, index=True, help="Use selection as refer_type in res_doctype", ) date_value = fields.Date( string='Value Date', compute='_compute_document', store=True, help="If origin document have value date. Otherwise, use move date", ) invoice_ids = fields.One2many( 'account.invoice', 'move_id', string='Invoice', readonly=True, ) invoice_cancel_ids = fields.One2many( 'account.invoice', 'cancel_move_id', string='Invoice Cancel', readonly=True, ) invoice_clear_prepaid_ids = fields.One2many( 'account.invoice', 'clear_prepaid_move_id', string='Invoice Clear Prepaid', readonly=True, ) voucher_ids = fields.One2many( 'account.voucher', 'move_id', string='Payment', readonly=True, ) voucher_cancel_ids = fields.One2many( 'account.voucher', 'cancel_move_id', string='Payment Cancel', readonly=True, ) voucher_recognize_vat_ids = fields.One2many( 'account.voucher', 'recognize_vat_move_id', string='Payment Recognize VAT', readonly=True, ) bank_receipt_ids = fields.One2many( 'account.bank.receipt', 'move_id', string='Bank Receipt', readonly=True, ) bank_receipt_cancel_ids = fields.One2many( 'account.bank.receipt', 'cancel_move_id', string='Bank Receipt Cancel', readonly=True, ) salary_expense_ids = fields.One2many( 'hr.salary.expense', 'move_id', string='Salary Expense', readonly=True, ) salary_expense_cancel_ids = fields.One2many( 'hr.salary.expense', 'cancel_move_id', string='Salary Expense Cancel', readonly=True, ) expense_rev_ic_ids = fields.One2many( 'hr.expense.expense', 'rev_ic_move_id', string='IC Revenue', readonly=True, ) expense_exp_ic_ids = fields.One2many( 'hr.expense.expense', 'exp_ic_move_id', string='IC Expense', readonly=True, ) account_interface_ids = fields.One2many( 'interface.account.entry', 'move_id', string='Account Interface', readonly=True, ) @api.multi @api.depends('invoice_ids.internal_number', 'invoice_cancel_ids.internal_number', 'invoice_clear_prepaid_ids.internal_number', 'voucher_ids.number', 'voucher_cancel_ids.number', 'voucher_recognize_vat_ids.number', 'bank_receipt_ids.name', 'bank_receipt_cancel_ids.name', 'salary_expense_ids.name', 'salary_expense_cancel_ids.name', 'expense_rev_ic_ids.number', 'expense_exp_ic_ids.number', 'account_interface_ids.number', 'ref', # check for stock.picking case, as it has no move_id ) def _compute_document(self): for rec in self: document = False # Invoice if rec.invoice_ids: document = rec.invoice_ids[0] elif rec.invoice_cancel_ids: document = rec.invoice_cancel_ids[0] elif rec.invoice_clear_prepaid_ids: document = rec.invoice_clear_prepaid_ids[0] # Voucher elif rec.voucher_ids: document = rec.voucher_ids[0] elif rec.voucher_cancel_ids: document = rec.voucher_cancel_ids[0] elif rec.voucher_recognize_vat_ids: document = rec.voucher_recognize_vat_ids[0] # Bank Receipt elif rec.bank_receipt_ids: document = rec.bank_receipt_ids[0] elif rec.bank_receipt_cancel_ids: document = rec.bank_receipt_cancel_ids[0] # Salary Expense elif rec.salary_expense_ids: document = rec.salary_expense_ids[0] elif rec.salary_expense_cancel_ids: document = rec.salary_expense_cancel_ids[0] # Expense IC elif rec.expense_rev_ic_ids: document = rec.expense_rev_ic_ids[0] elif rec.expense_exp_ic_ids: document = rec.expense_exp_ic_ids[0] # Account Interface elif rec.account_interface_ids: document = rec.account_interface_ids[0] elif rec.ref: # Last chance for picking, as it not have move_id Picking = self.env['stock.picking'] picking = Picking.search([('name', '=', rec.ref)]) document = picking and picking[0] or False # Assign reference if document: rec.document_id = '%s,%s' % (document._name, document.id) if document._name in ('stock.picking', 'account.bank.receipt'): rec.document = document.name elif document._name == 'account.invoice': rec.document = document.internal_number else: rec.document = document.number rec.doctype = self._get_doctype(document._name, document) if 'date_value' in document._fields: rec.date_value = document.date_value else: rec.doctype = 'adjustment' # <-- Not related to any doc if not rec.date_value: rec.date_value = rec.date # No Value Date, same as date @api.model def _get_doctype(self, model, document): if model == 'account.invoice': return INVOICE_DOCTYPE[document.journal_id.type] if model == 'account.voucher': return VOUCHER_DOCTYPE[document.type] if model == 'account.bank.receipt': return 'bank_receipt' if model == 'hr.expense.expense': return 'employee_expense' if model == 'hr.salary.expense': return 'salary_expense' if model == 'stock.picking': return PICKING_DOCTYPE[document.picking_type_id.code] if model == 'interface.account.entry': return 'interface_account'
class BudgetPlanUnitLine(BPLMonthCommon, ActivityCommon, models.Model): _name = 'budget.plan.unit.line' _description = "Unit - Budget Plan Line" _rec_name = 'activity_group_id' charge_type = fields.Selection( [('internal', 'Internal'), ('external', 'External')], string='Charge Type', required=True, default='external', help="Specify whether the budget plan line is for Internal Charge or " "External Charge. Internal charged is for Unit Based only.") # COMMON chart_view = fields.Selection( default='unit_base', # Unit ) plan_id = fields.Many2one( 'budget.plan.unit', string='Budget Plan', ondelete='cascade', index=True, required=True, ) # Extra section_id = fields.Many2one( related='plan_id.section_id', string='Section', store=True, readonly=True, ) section_name = fields.Char( related='section_id.name', string='Section Name', store=True, readonly=True, ) section_name_short = fields.Char( related='section_id.name_short', string='Section Alias', store=True, readonly=True, ) section_code = fields.Char( related='section_id.code', string='Section Code', store=True, readonly=True, ) section_program_id = fields.Many2one( related='plan_id.section_id.section_program_id', string='Section Program', store=True, readonly=True, ) mission_id = fields.Many2one( related='section_id.mission_id', string='Mission', store=True, readonly=True, ) # program_rpt_id = fields.Many2one( # related='section_id.program_rpt_id', # string='Program', # store=True, # readonly=True, # ) division_id = fields.Many2one( related='plan_id.section_id.division_id', store=True, readonly=True, ) subsector_id = fields.Many2one( related='plan_id.section_id.subsector_id', store=True, readonly=True, ) sector_id = fields.Many2one( related='plan_id.section_id.sector_id', store=True, readonly=True, ) org_id = fields.Many2one( related='plan_id.section_id.org_id', store=True, readonly=True, ) cost_control_type_id = fields.Many2one( related='cost_control_id.cost_control_type_id', store=True, readonly=True, ) unit = fields.Float(string='Unit', ) activity_unit_price = fields.Float(string='Unit Price', ) activity_unit = fields.Float(string='Activity Unit', ) total_budget = fields.Float(string='Total Budget', ) cost_control_code = fields.Char( related='cost_control_id.code', string='Job Order Code', readonly=True, store=True, ) cost_control_name = fields.Char( related='cost_control_id.name', string='Job Order Name', readonly=True, store=True, ) reason = fields.Text(string='Reason', ) # Converted to equivalant status # status = fields.Selection( # _STATUS, # related='plan_id.status', # string='Status', # store=True, # help="This virtual field is being used to sort the status in view", # ) next_fy_commitment = fields.Float( string='Next FY Commitment', readonly=True, help="Comitment on next fy PR/PO/EX", ) @api.model def search(self, args, offset=0, limit=None, order=None, count=False): """ Add additional filter criteria """ return super(BudgetPlanUnitLine, self).search(self.search_args(args), offset=offset, limit=limit, order=order, count=count)
class SaasServerClient(models.Model): _name = 'saas_server.client' _inherit = ['mail.thread', 'saas_base.client'] name = fields.Char('Database name', readonly=True) client_id = fields.Char('Database UUID', readonly=True, select=True) state = fields.Selection([('template', 'Template'), ('draft','New'), ('open','In Progress'), ('cancelled', 'Cancelled'), ('pending','Pending'), ('deleted','Deleted')], 'State', default='draft', track_visibility='onchange') _sql_constraints = [ ('client_id_uniq', 'unique (client_id)', 'client_id should be unique!'), ] @api.one def create_database(self, template_db=None, demo=False, lang='en_US'): new_db = self.name if template_db: openerp.service.db._drop_conn(self.env.cr, template_db) openerp.service.db.exp_duplicate_database(template_db, new_db) else: password = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(32)) openerp.service.db.exp_create_database(new_db, demo, lang, user_password=password) self.state = 'open' @api.one def registry(self, new=False, **kwargs): m = openerp.modules.registry.RegistryManager if new: return m.new(self.name, **kwargs) else: return m.get(self.name, **kwargs) @api.one def install_addons(self, addons, is_template_db): addons = set(addons) addons.add('mail_delete_sent_by_footer') # debug if is_template_db: addons.add('auth_oauth') addons.add('saas_client') else: addons.add('saas_client') if not addons: return with self.registry()[0].cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, self._context) self._install_addons(env, addons) @api.one def disable_mail_servers(self): ''' disables mailserver on db to stop it from sending and receiving mails ''' # let's disable incoming mail servers incoming_mail_servers = self.env['fetchmail.server'].search([]) if len(incoming_mail_servers): incoming_mail_servers.write({'active': False}) # let's disable outgoing mailservers too outgoing_mail_servers = self.env['ir.mail_server'].search([]) if len(outgoing_mail_servers): outgoing_mail_servers.write({'active': False}) @api.one def _install_addons(self, client_env, addons): for addon in client_env['ir.module.module'].search([('name', 'in', list(addons))]): addon.button_install() @api.one def update_registry(self): self.registry(new=True, update_module=True) @api.one def prepare_database(self, **kwargs): with self.registry()[0].cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, self._context) self._prepare_database(env, **kwargs) @api.model def _config_parameters_to_copy(self): return ['saas_client.ab_location', 'saas_client.ab_register'] @api.one def _prepare_database(self, client_env, saas_portal_user=None, is_template_db=False, addons=[], access_token=None, tz=None): client_id = self.client_id # update saas_server.client state if is_template_db: self.state = 'template' # set tz if tz: client_env['res.users'].search([]).write({'tz': tz}) client_env['ir.values'].set_default('res.partner', 'tz', tz) # update database.uuid client_env['ir.config_parameter'].set_param('database.uuid', client_id) # copy configs for key in self._config_parameters_to_copy(): value = self.env['ir.config_parameter'].get_param(key, default='') client_env['ir.config_parameter'].set_param(key, value) # copy auth provider from saas_server saas_oauth_provider = self.env.ref('saas_server.saas_oauth_provider') oauth_provider = None if is_template_db and not client_env.ref('saas_server.saas_oauth_provider', raise_if_not_found=False): oauth_provider_data = {'enabled': False, 'client_id': client_id} for attr in ['name', 'auth_endpoint', 'scope', 'validation_endpoint', 'data_endpoint', 'css_class', 'body']: oauth_provider_data[attr] = getattr(saas_oauth_provider, attr) oauth_provider = client_env['auth.oauth.provider'].create(oauth_provider_data) client_env['ir.model.data'].create({ 'name': 'saas_oauth_provider', 'module': 'saas_server', 'noupdate': True, 'model': 'auth.oauth.provider', 'res_id': oauth_provider.id, }) if not oauth_provider: oauth_provider = client_env.ref('saas_server.saas_oauth_provider') if not is_template_db: oauth_provider.client_id = client_id # prepare users OWNER_TEMPLATE_LOGIN = '******' user = None if is_template_db: client_env['res.users'].create({ 'login': OWNER_TEMPLATE_LOGIN, 'name': 'NAME', 'email': '*****@*****.**', }) client_env['res.users'].browse(SUPERUSER_ID).write({ 'oauth_provider_id': oauth_provider.id, 'oauth_uid': SUPERUSER_ID, 'oauth_access_token': access_token }) else: domain = [('login', '=', OWNER_TEMPLATE_LOGIN)] res = client_env['res.users'].search(domain) if res: user = res[0] res = client_env['res.users'].search([('login', '=', saas_portal_user['email'])]) if res: # user already exists (e.g. administrator) user = res[0] if not user: user = client_env['res.users'].browse(SUPERUSER_ID) user.write({ 'login': saas_portal_user['email'], 'name': saas_portal_user['name'], 'email': saas_portal_user['email'], 'oauth_provider_id': oauth_provider.id, 'oauth_uid': saas_portal_user['user_id'], 'oauth_access_token': access_token }) @api.model def update_all(self): self.sudo().search([]).update() @api.one def update(self): try: registry = self.registry()[0] except psycopg2.OperationalError: if self.state != 'draft': self.state = 'deleted' return with registry.cursor() as client_cr: client_env = api.Environment(client_cr, SUPERUSER_ID, self._context) data = self._get_data(client_env, self.client_id)[0] self.write(data) @api.one def _get_data(self, client_env, check_client_id): client_id = client_env['ir.config_parameter'].get_param('database.uuid') if check_client_id != client_id: return {'state': 'deleted'} users = client_env['res.users'].search([('share', '=', False)]) users_len = len(users) data_dir = openerp.tools.config['data_dir'] file_storage = get_size('%s/filestore/%s' % (data_dir, self.name)) file_storage = int(file_storage / (1024 * 1024)) client_env.cr.execute("select pg_database_size('%s')" % self.name) db_storage = client_env.cr.fetchone()[0] db_storage = int(db_storage / (1024 * 1024)) data = { 'client_id': client_id, 'users_len': users_len, 'file_storage': file_storage, 'db_storage': db_storage, } return data @api.one def upgrade_database(self, **kwargs): with self.registry()[0].cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, self._context) return self._upgrade_database(env, **kwargs)[0] @api.one def _upgrade_database(self, client_env, data): # "data" comes from saas_portal/models/wizard.py::upgrade_database post = data module = client_env['ir.module.module'] print '_upgrade_database', data # 1. Update addons update_addons = post.get('update_addons', []) if update_addons: module.search([('name', 'in', update_addons)]).button_immediate_upgrade() # 2. Install addons install_addons = post.get('install_addons', []) if install_addons: module.search([('name', 'in', install_addons)]).button_immediate_install() # 3. Uninstall addons uninstall_addons = post.get('uninstall_addons', []) if uninstall_addons: module.search([('name', 'in', uninstall_addons)]).button_immediate_uninstall() # 4. Run fixes fixes = post.get('fixes', []) for model, method in fixes: getattr(request.registry[model], method)() # 5. update parameters params = post.get('params', []) for key, value in params: client_env['ir.config_parameter'].set_param(key, value) return 'OK' @api.model def delete_expired_databases(self): now = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) res = self.search([('state','not in', ['deleted']), ('expiration_datetime', '<=', now)]) _logger.info('delete_expired_databases %s', res) res.delete_database() @api.one def delete_database(self): openerp.service.db.exp_drop(self.name) self.write({'state': 'deleted'})
class employee_data_export(models.TransientModel): _name = 'employee.data.export' name = fields.Binary('Timesheet CSV') file_name = fields.Char('File') report_selection = fields.Selection( [('export_employee', 'Personalübersicht'), ('export_workcouncil', 'BR Übersicht')], string='Report', default='export_employee', required=True) @api.multi def export_emp_data_csv(self): """ This function is use to export the employee data records which are preselected. """ if self._context and 'active_model' in self._context and self._context[ 'active_model'] == 'hr.employee': context = self._context.copy() hr_employee = self.env['hr.employee'] if self.report_selection == 'export_workcouncil': hr_employee_records = hr_employee.search([ ('executive_employee', '=', False), ('id', 'in', context['active_ids']) ]) else: hr_employee_records = hr_employee.browse(context['active_ids']) # print"analytic_timesheet_records----",analytic_timesheet_records context = self.export_csv_subfunction(hr_employee_records) return { 'name': _('Exported Employee Data'), 'view_type': 'form', "view_mode": 'form', 'res_model': 'employee.data.export', 'type': 'ir.actions.act_window', 'context': context, 'target': 'new', } def get_date_format(self, date): if date: return datetime.strptime(date, '%Y-%m-%d').strftime('%d.%m.%Y') else: return '' def export_csv_subfunction(self, emp_data_records): """ It is a subfunction for the export csv. """ data_list = [] if self._context.get( 'for_work_council' ) or self.report_selection == 'export_workcouncil': csv_header = [ 'Personalnummer', 'Vorname', 'Nachname', 'Bereich', 'Team', 'Stellenbezeichnung', 'Vertragstyp', 'Ersteintrittsdatum', 'Enddatum befristeter Vertrag', 'Befristungsgrund', 'Probezeit Enddatum', 'letztes MA Gespraech', ] csv_name = "Betriebsratsübersicht" else: csv_header = [ 'Personalnummer', 'Vorname', 'Nachname', 'Geburtstag', 'Company', 'Bereich', 'Team', 'Planstellenbezeichnung', 'Stellenbezeichnung', 'Vertragstyp', 'Ersteintrittsdatum', 'Enddatum befristeter Vertrag', 'Befristungsgrund', 'Probezeit Enddatum', 'letztes MA Gespraech', '5-Jahresjubilaeum', 'Arbeitszeit', 'Urlaub', 'Schwerbehinderung', 'letzte Vertragsaenderung_L&G', 'Startdatum der letzten Vertragversänderung', 'Verguetung', 'Verguetung bei VZ', 'Verguetung inkl. AG Kosten (25%)', 'BR Mitglied', 'Bemerkungen', 'Manager' ] csv_name = "Personalübersicht" time_csv = datetime.now().strftime('%Y-%m-%d_%H%M%S') + '.csv' csv_path = "/tmp/" + time_csv for emp_record in emp_data_records: if self._context.get( 'for_work_council' ) or self.report_selection == 'export_workcouncil': vals = { 'Personalnummer': (emp_record.identification_id or '').encode('utf-8'), 'Nachname': (emp_record.second_name or '').encode('utf-8'), 'Vorname': (emp_record.surname or '').encode('utf-8'), 'Bereich': (emp_record.bereich and emp_record.bereich.name or '').encode('utf-8'), 'Team': (emp_record.department_id and emp_record.department_id.name or '').encode('utf-8'), 'Stellenbezeichnung': (emp_record.job_id and emp_record.job_id.name or '').encode('utf-8'), 'Vertragstyp': (emp_record.sudo().contract_type and emp_record.sudo().contract_type.name or '').encode('utf-8'), 'Ersteintrittsdatum': self.get_date_format(emp_record.initial_date), 'Enddatum befristeter Vertrag': self.get_date_format(emp_record.temp_contract_end_date), 'Befristungsgrund': (emp_record.contract_limitation_reason and emp_record.contract_limitation_reason.name or '').encode('utf-8'), 'Probezeit Enddatum': self.get_date_format(emp_record.contract_trial_end_date), 'letztes MA Gespraech': self.get_date_format(emp_record.last_ma_conversation_date), } else: notes = '' if emp_record.contract_notes: notes = emp_record.contract_notes.replace("\n", " / ") vals = { 'Personalnummer': (emp_record.identification_id or '').encode('utf-8'), 'Nachname': (emp_record.second_name or '').encode('utf-8'), 'Vorname': (emp_record.surname or '').encode('utf-8'), 'Geburtstag': self.get_date_format(emp_record.birthday), 'Company': (emp_record.address_id and emp_record.address_id.sudo().name or '').encode('utf-8'), 'Bereich': (emp_record.bereich and emp_record.bereich.name or '').encode('utf-8'), 'Team': (emp_record.department_id and emp_record.department_id.name or '').encode('utf-8'), 'Planstellenbezeichnung': (emp_record.planned_job_id and emp_record.planned_job_id.name or '').encode('utf-8'), 'Stellenbezeichnung': (emp_record.job_id and emp_record.job_id.name or '').encode('utf-8'), 'Vertragstyp': (emp_record.sudo().contract_type and emp_record.sudo().contract_type.name or '').encode('utf-8'), 'Ersteintrittsdatum': self.get_date_format(emp_record.initial_date), 'Enddatum befristeter Vertrag': self.get_date_format(emp_record.temp_contract_end_date), 'Befristungsgrund': (emp_record.contract_limitation_reason and emp_record.contract_limitation_reason.name or '').encode('utf-8'), 'Probezeit Enddatum': self.get_date_format(emp_record.contract_trial_end_date), 'letztes MA Gespraech': self.get_date_format(emp_record.last_ma_conversation_date), '5-Jahresjubilaeum': self.get_date_format(emp_record.five_years), 'Arbeitszeit': (emp_record.contract_working_hours and emp_record.contract_working_hours.name or '').encode('utf-8'), 'Urlaub': emp_record.contract_leaves or '', 'Schwerbehinderung': ('ja' if emp_record.disability == 'yes' else 'nein' or ''), # 'letzte Vertragsaenderung_L&G': emp_record.last_contract_changed_wage or '', 'letzte Vertragsaenderung_L&G': ("%.2f" % emp_record.last_contract_changed_wage).replace( '.', ',') or '', 'Startdatum der letzten Vertragversänderung': self.get_date_format( emp_record.last_contract_changed_date), 'Verguetung': ("%.2f" % emp_record.emp_wage_cal).replace('.', ',') or '', # 'Verguetung bei VZ': emp_record.compensation_at_vz or '', 'Verguetung bei VZ': ("%.2f" % emp_record.compensation_at_vz).replace('.', ',') or '', # 'Verguetung inkl. AG Kosten (25%)': emp_record.remuneration_incl_ag_costs or '', 'Verguetung inkl. AG Kosten (25%)': ("%.2f" % emp_record.remuneration_incl_ag_costs).replace( '.', ',') or '', 'BR Mitglied': ('ja' if emp_record.br_member == 'yes' else 'nein' or '').encode('utf-8'), 'Bemerkungen': (notes).encode('utf-8'), 'Manager': (emp_record.parent_id and emp_record.parent_id.name or '').encode('utf-8'), } data_list.append(vals) with open(csv_path, 'wb') as csvfile: w = csv.DictWriter(csvfile, fieldnames=csv_header, delimiter=';', quoting=csv.QUOTE_ALL) w.writeheader() w.writerows(data_list) csvfile.close() data = '' with open(csv_path, 'rb') as csvfile: data = csvfile.read() data = data.encode('base64') csvfile.close() context = self._context.copy() file_name = datetime.now().strftime( '%Y%m%d_%H_%M') + '_' + csv_name + '.csv' context.update({'default_name': data, 'default_file_name': file_name}) os.remove(csv_path) return context
class GithubRepositoryBranch(models.Model): _name = 'github.repository.branch' _inherit = ['github.connector'] _order = 'complete_name' _SELECTION_STATE = [ ('to_download', 'To Download'), ('to_analyze', 'To Analyze'), ('analyzed', 'Analyzed'), ] # Column Section name = fields.Char(string='Name', select=True, required=True, readonly=True) complete_name = fields.Char(string='Complete Name', compute='_compute_complete_name', store=True) state = fields.Selection(string='State', selection=_SELECTION_STATE, default='to_download') repository_id = fields.Many2one(comodel_name='github.repository', string='Repository', required=True, select=True, readonly=True, ondelete='cascade') organization_id = fields.Many2one(comodel_name='github.organization', string='Organization', related='repository_id.organization_id', store=True, readonly=True) last_download_date = fields.Datetime(string='Last Download Date') last_analyze_date = fields.Datetime(string='Last Analyze Date') module_paths = fields.Text( string='Module Paths', help="Set here extra relative paths" " you want to scan to find modules. If not set, root path will be" " scanned. One repository per line. Exemple:\n" "./addons/\n" "./openerp/addons/") module_version_ids = fields.One2many(comodel_name='oca.module.version', inverse_name='repository_branch_id', string='Module Versions') module_version_qty = fields.Integer(string='Module Versions Quantity', compute='compute_module_version_qty') # Compute Section @api.multi @api.depends('name', 'repository_id.complete_name') def _compute_complete_name(self): for repository_branch in self: repository_branch.complete_name =\ repository_branch.repository_id.complete_name +\ '/' + repository_branch.name # Compute Section @api.one def name_get(self): return [self.id, self.complete_name] @api.multi @api.depends('module_version_ids', 'module_version_ids.repository_branch_id') def compute_module_version_qty(self): for repository_branch in self: repository_branch.module_version_qty =\ len(repository_branch.module_version_ids) # Action Section @api.multi def button_download_code(self): return self._download_code() @api.multi def button_update_code(self): return self._download_code() @api.multi def button_analyze_code(self): return self._analyze_code() # Custom Section def create_or_update_from_name(self, repository_id, name): repository_branch = self.search([('name', '=', name), ('repository_id', '=', repository_id) ]) if not repository_branch: repository_branch = self.create({ 'name': name, 'repository_id': repository_id }) return repository_branch def _download_code(self): for repository_branch in self: path = self._get_local_path(repository_branch.complete_name) if not os.path.exists(path): _logger.info("Cloning new repository into %s ..." % (path)) # Cloning the repository os.makedirs(path) os.system("cd %s &&" " git clone https://github.com/%s.git -b %s ." % (path, repository_branch.repository_id.complete_name, repository_branch.name)) repository_branch.write({ 'last_download_date': datetime.today(), 'state': 'to_analyze', }) else: # Update repository _logger.info("Pulling existing repository %s ..." % (path)) try: res = check_output( ['git', 'pull', 'origin', repository_branch.name], cwd=path) except: raise exceptions.Warning( _("Git Access Error"), _("Unable to access to pull repository in %s.") % (path)) if repository_branch.state == 'to_download' or\ 'up-to-date' not in res: repository_branch.write({ 'last_download_date': datetime.today(), 'state': 'to_analyze', }) else: repository_branch.write({ 'last_download_date': datetime.today(), }) self._cr.commit() @api.multi def _analyze_code(self): module_version_obj = self.env['oca.module.version'] for repository_branch in self: # Delete all associated module versions module_versions = module_version_obj.search([ ('repository_branch_id', '=', repository_branch.id) ]) module_versions.with_context( dont_change_repository_branch_state=True).unlink() # Compute path(s) to analyze if repository_branch.module_paths: paths = [] for path in repository_branch.module_paths.split('\n'): if path.strip(): paths.append( self._get_local_path( repository_branch.complete_name) + '/' + path) else: paths = [self._get_local_path(repository_branch.complete_name)] # Scan each path, if exists for path in paths: if not os.path.exists(path): _logger.warning( "Unable to analyse %s. Source code not found." % (path)) else: # Scan folder _logger.info("Analyzing repository %s ..." % (path)) for module_name in self.listdir(path): module_info = load_information_from_description_file( module_name, path + '/' + module_name) # Create module version, if the module is installable # in the serie if module_info.get('installable', False): module_info['name'] = module_name module_version_obj.create_or_update_from_manifest( module_info, repository_branch) self._cr.commit() repository_branch.write({ 'last_analyze_date': datetime.today(), 'state': 'analyzed', }) self._cr.commit() # Copy Paste from Odoo Core # This function is for the time being in another function. # (Ref: openerp/modules/module.py) def listdir(self, dir): def clean(name): name = os.path.basename(name) if name[-4:] == '.zip': name = name[:-4] return name def is_really_module(name): manifest_name = opj(dir, name, MANIFEST) return os.path.isfile(manifest_name) return map(clean, filter(is_really_module, os.listdir(dir)))
class event_registration(models.Model): _name = 'event.registration' _description = 'Attendee' _inherit = ['mail.thread', 'ir.needaction_mixin'] _order = 'name, create_date desc' origin = fields.Char( string='Source Document', readonly=True, help= "Reference of the document that created the registration, for example a sale order" ) event_id = fields.Many2one('event.event', string='Event', required=True, readonly=True, states={'draft': [('readonly', False)]}) partner_id = fields.Many2one('res.partner', string='Contact', states={'done': [('readonly', True)]}) date_open = fields.Datetime(string='Registration Date', readonly=True, default=lambda self: fields.datetime.now() ) # weird crash is directly now date_closed = fields.Datetime(string='Attended Date', readonly=True) event_begin_date = fields.Datetime(string="Event Start Date", related='event_id.date_begin', readonly=True) event_end_date = fields.Datetime(string="Event End Date", related='event_id.date_end', readonly=True) company_id = fields.Many2one('res.company', string='Company', related='event_id.company_id', store=True, readonly=True, states={'draft': [('readonly', False)]}) state = fields.Selection([('draft', 'Unconfirmed'), ('cancel', 'Cancelled'), ('open', 'Confirmed'), ('done', 'Attended')], string='Status', default='draft', readonly=True, copy=False, track_visibility='onchange') email = fields.Char(string='Email') phone = fields.Char(string='Phone') name = fields.Char(string='Attendee Name', select=True) @api.one @api.constrains('event_id', 'state') def _check_seats_limit(self): if self.event_id.seats_max and self.event_id.seats_available < ( 1 if self.state == 'draft' else 0): raise UserError(_('No more seats available for this event.')) @api.multi def _check_auto_confirmation(self): if self._context.get('registration_force_draft'): return False if any(registration.event_id.state != 'confirm' or not registration.event_id.auto_confirm or not registration.event_id.seats_available for registration in self): return False return True @api.model def create(self, vals): registration = super(event_registration, self).create(vals) if registration._check_auto_confirmation(): registration.sudo().confirm_registration() return registration @api.one def do_draft(self): self.state = 'draft' @api.one def confirm_registration(self): self.event_id.message_post(body=_('New registration confirmed: %s.') % (self.name or ''), subtype="event.mt_event_registration") self.state = 'open' @api.one def button_reg_close(self): """ Close Registration """ today = fields.Datetime.now() if self.event_id.date_begin <= today: self.write({'state': 'done', 'date_closed': today}) else: raise UserError( _("You must wait for the starting day of the event to do this action." )) @api.one def button_reg_cancel(self): self.state = 'cancel' @api.onchange('partner_id') def _onchange_partner(self): if self.partner_id: contact_id = self.partner_id.address_get().get('default', False) if contact_id: contact = self.env['res.partner'].browse(contact_id) self.name = self.name or contact.name self.email = self.email or contact.email self.phone = self.phone or contact.phone @api.multi def message_get_suggested_recipients(self): recipients = super(event_registration, self).message_get_suggested_recipients() for attendee in self: if attendee.email: self._message_add_suggested_recipient( recipients, attendee, email=attendee.email, reason=_('Customer Email')) if attendee.partner_id: self._message_add_suggested_recipient( recipients, attendee, partner=attendee.partner_id, reason=_('Customer')) return recipients
class LunchOrderLine(models.Model): _name = 'lunch.order.line' _description = 'lunch order line' name = fields.Char(related='product_id.name', string="Product Name", readonly=True) order_id = fields.Many2one('lunch.order', 'Order', ondelete='cascade', required=True) product_id = fields.Many2one('lunch.product', 'Product', required=True) category_id = fields.Many2one('lunch.product.category', string='Product Category', related='product_id.category_id', readonly=True, store=True) date = fields.Date(string='Date', related='order_id.date', readonly=True, store=True) supplier = fields.Many2one('res.partner', string='Vendor', related='product_id.supplier', readonly=True, store=True) user_id = fields.Many2one('res.users', string='User', related='order_id.user_id', readonly=True, store=True) note = fields.Text('Note') price = fields.Float(related='product_id.price', readonly=True, store=True, digits=dp.get_precision('Account')) state = fields.Selection([('new', 'New'), ('confirmed', 'Received'), ('ordered', 'Ordered'), ('cancelled', 'Cancelled')], 'Status', readonly=True, select=True, default='new') cashmove = fields.One2many('lunch.cashmove', 'order_id', 'Cash Move') currency_id = fields.Many2one('res.currency', related='order_id.currency_id') @api.one def order(self): """ The order_line is ordered to the vendor but isn't received yet """ if self.user_has_groups("lunch.group_lunch_manager"): self.state = 'ordered' else: raise AccessError(_("Only your lunch manager processes the orders.")) @api.one def confirm(self): """ confirm one or more order line, update order status and create new cashmove """ if self.user_has_groups("lunch.group_lunch_manager"): if self.state != 'confirmed': values = { 'user_id': self.user_id.id, 'amount': -self.price, 'description': self.product_id.name, 'order_id': self.id, 'state': 'order', 'date': self.date, } self.env['lunch.cashmove'].create(values) self.state = 'confirmed' else: raise AccessError(_("Only your lunch manager sets the orders as received.")) @api.one def cancel(self): """ cancel one or more order.line, update order status and unlink existing cashmoves """ if self.user_has_groups("lunch.group_lunch_manager"): self.state = 'cancelled' self.cashmove.unlink() else: raise AccessError(_("Only your lunch manager cancels the orders."))