From b92c6b3101e2d58c12cc74923bb1a8771a06c4bd Mon Sep 17 00:00:00 2001 From: qdp-odoo Date: Fri, 21 Nov 2014 10:09:29 +0100 Subject: [PATCH] [IMP] base, ir_sequence: added use_date_range field on ir.sequence, that allows to have several sequences running for the same one depending on date ranges (similar to what was existing previously on accounting with FY, which is now deprecated) + port to new API --- addons/account/__init__.py | 1 - addons/account/__openerp__.py | 1 - addons/account/account.py | 5 +- addons/account/ir_sequence.py | 60 --- addons/account/ir_sequence_view.xml | 27 -- addons/account/security/ir.model.access.csv | 4 - addons/account_asset/account_asset.py | 2 +- .../account_bank_statement.py | 2 +- addons/account_payment/account_payment.py | 6 +- addons/analytic/models/analytic.py | 2 +- addons/hr_payroll/hr_payroll.py | 2 +- .../wizard/l10n_be_partner_vat_listing.py | 4 +- addons/l10n_be/wizard/l10n_be_vat_intra.py | 2 +- .../l10n_in_hr_payroll/l10n_in_hr_payroll.py | 2 +- addons/mrp/mrp.py | 2 +- addons/mrp/security/ir.model.access.csv | 3 - addons/mrp_repair/mrp_repair.py | 2 +- addons/point_of_sale/point_of_sale.py | 6 +- .../security/ir.model.access.csv | 1 - addons/procurement/procurement.py | 2 +- addons/purchase/purchase.py | 4 +- addons/purchase/security/ir.model.access.csv | 1 - .../purchase_requisition.py | 2 +- addons/sale/sale.py | 2 +- addons/stock/stock.py | 8 +- .../stock_landed_costs/stock_landed_costs.py | 2 +- .../stock_picking_wave/stock_picking_wave.py | 2 +- openerp/addons/base/ir/ir_sequence.py | 398 +++++++++++------- openerp/addons/base/ir/ir_sequence_view.xml | 10 +- .../addons/base/security/ir.model.access.csv | 2 + 30 files changed, 286 insertions(+), 281 deletions(-) delete mode 100644 addons/account/ir_sequence.py delete mode 100644 addons/account/ir_sequence_view.xml diff --git a/addons/account/__init__.py b/addons/account/__init__.py index 3d6f6061a72..15a3bc81cf4 100644 --- a/addons/account/__init__.py +++ b/addons/account/__init__.py @@ -32,7 +32,6 @@ import account_financial_report import wizard import report import product -import ir_sequence import company import res_currency import edi diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index 45c02f2f2d4..77bbdc394f5 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -107,7 +107,6 @@ for a particular financial year and for preparation of vouchers there is a modul 'product_view.xml', 'account_assert_test.xml', 'account_analytic_view.xml', - 'ir_sequence_view.xml', 'company_view.xml', 'edi/invoice_action_data.xml', 'account_bank_view.xml', diff --git a/addons/account/account.py b/addons/account/account.py index d4c34f49922..555d54c3ece 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -812,7 +812,8 @@ class account_journal(osv.osv): 'implementation':'no_gap', 'prefix': prefix + "/%(year)s/", 'padding': 4, - 'number_increment': 1 + 'number_increment': 1, + 'use_date_range': True, } if 'company_id' in vals: seq['company_id'] = vals['company_id'] @@ -1631,7 +1632,7 @@ class account_move_reconcile(osv.osv): 'opening_reconciliation': fields.boolean('Opening Entries Reconciliation', help="Is this reconciliation produced by the opening of a new fiscal year ?."), } _defaults = { - 'name': lambda self,cr,uid,ctx=None: self.pool.get('ir.sequence').get(cr, uid, 'account.reconcile', context=ctx) or '/', + 'name': lambda self,cr,uid,ctx=None: self.pool.get('ir.sequence').next_by_code(cr, uid, 'account.reconcile', context=ctx) or '/', } # You cannot unlink a reconciliation if it is a opening_reconciliation one, diff --git a/addons/account/ir_sequence.py b/addons/account/ir_sequence.py deleted file mode 100644 index 19d7ee0cf87..00000000000 --- a/addons/account/ir_sequence.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp import api -from openerp.osv import fields, osv - -class ir_sequence_fiscalyear(osv.osv): - _name = 'account.sequence.fiscalyear' - _rec_name = "sequence_main_id" - _columns = { - "sequence_id": fields.many2one("ir.sequence", 'Sequence', required=True, - ondelete='cascade'), - "sequence_main_id": fields.many2one("ir.sequence", 'Main Sequence', - required=True, ondelete='cascade'), - "fiscalyear_id": fields.many2one('account.fiscalyear', 'Fiscal Year', - required=True, ondelete='cascade') - } - - _sql_constraints = [ - ('main_id', 'CHECK (sequence_main_id != sequence_id)', - 'Main Sequence must be different from current !'), - ] - - -class ir_sequence(osv.osv): - _inherit = 'ir.sequence' - _columns = { - 'fiscal_ids': fields.one2many('account.sequence.fiscalyear', - 'sequence_main_id', 'Sequences', copy=True) - } - - @api.cr_uid_ids_context - def _next(self, cr, uid, seq_ids, context=None): - if context is None: - context = {} - for seq in self.browse(cr, uid, seq_ids, context): - for line in seq.fiscal_ids: - if line.fiscalyear_id.id == context.get('fiscalyear_id'): - return super(ir_sequence, self)._next(cr, uid, [line.sequence_id.id], context) - return super(ir_sequence, self)._next(cr, uid, seq_ids, context) - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/ir_sequence_view.xml b/addons/account/ir_sequence_view.xml deleted file mode 100644 index bae969ed199..00000000000 --- a/addons/account/ir_sequence_view.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - ir.sequence.form - ir.sequence - - - - - - - - - -
- - - - -
-
-
-
- -
-
diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv index d35d227c869..b68d6e3f0a1 100644 --- a/addons/account/security/ir.model.access.csv +++ b/addons/account/security/ir.model.access.csv @@ -62,7 +62,6 @@ access_account_fiscal_position_account,account.fiscal.position all,model_account access_account_fiscal_position_template,account.fiscal.position.template,model_account_fiscal_position_template,account.group_account_manager,1,1,1,1 access_account_fiscal_position_tax_template,account.fiscal.position.tax.template,model_account_fiscal_position_tax_template,account.group_account_manager,1,1,1,1 access_account_fiscal_position_account_template,account.fiscal.position.account.template,model_account_fiscal_position_account_template,account.group_account_manager,1,1,1,1 -access_account_sequence_fiscal_year_user,account.sequence.fiscalyear user,model_account_sequence_fiscalyear,base.group_user,1,0,0,0 access_temp_range,temp.range,model_temp_range,account.group_account_manager,1,0,0,0 access_report_aged_receivable,report.aged.receivable,model_report_aged_receivable,account.group_account_manager,1,1,1,1 access_report_invoice_created,report.invoice.created,model_report_invoice_created,account.group_account_manager,1,1,1,1 @@ -88,12 +87,9 @@ access_account_account_invoice,account.account invoice,model_account_account,acc access_account_analytic_accountant,account.analytic.account accountant,analytic.model_account_analytic_account,account.group_account_user,1,1,1,1 access_account_account_type_invoice,account.account.type invoice,model_account_account_type,account.group_account_invoice,1,1,1,1 access_report_account_receivable_invoice,report.account.receivable.invoice,model_report_account_receivable,account.group_account_invoice,1,1,1,1 -access_account_sequence_fiscal_year_invoice,account.sequence.fiscalyear invoice,model_account_sequence_fiscalyear,account.group_account_invoice,1,1,1,1 access_account_tax_sale_manager,account.tax sale manager,model_account_tax,base.group_sale_salesman,1,0,0,0 access_account_journal_sale_manager,account.journal sale manager,model_account_journal,base.group_sale_salesman,1,0,0,0 access_account_invoice_tax_sale_manager,account.invoice.tax sale manager,model_account_invoice_tax,base.group_sale_salesman,1,0,0,0 -access_account_sequence_fiscal_year_sale_user,account.sequence.fiscalyear.sale.user,model_account_sequence_fiscalyear,base.group_sale_salesman,1,1,1,0 -access_account_sequence_fiscal_year_sale_manager,account.sequence.fiscalyear.sale.manager,model_account_sequence_fiscalyear,base.group_sale_manager,1,1,1,1 access_account_treasury_report_manager,account.treasury.report.manager,model_account_treasury_report,account.group_account_manager,1,0,0,0 access_account_financial_report,account.financial.report,model_account_financial_report,account.group_account_user,1,1,1,1 access_account_financial_report_invoice,account.financial.report invoice,model_account_financial_report,account.group_account_invoice,1,0,0,0 diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 7aa97bb012e..ab8b1f9bd6a 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -280,7 +280,7 @@ class account_asset_asset(osv.osv): 'salvage_value': fields.float('Salvage Value', digits_compute=dp.get_precision('Account'), help="It is the amount you plan to have that you cannot depreciate.", readonly=True, states={'draft':[('readonly',False)]}), } _defaults = { - 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'account.asset.code'), + 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'account.asset.code'), 'purchase_date': lambda obj, cr, uid, context: time.strftime('%Y-%m-%d'), 'active': True, 'state': 'draft', diff --git a/addons/account_bank_statement_extensions/account_bank_statement.py b/addons/account_bank_statement_extensions/account_bank_statement.py index 72c3320be38..e0e6e768aae 100644 --- a/addons/account_bank_statement_extensions/account_bank_statement.py +++ b/addons/account_bank_statement_extensions/account_bank_statement.py @@ -82,7 +82,7 @@ class account_bank_statement_line_global(osv.osv): } _rec_name = 'code' _defaults = { - 'code': lambda s,c,u,ctx={}: s.pool.get('ir.sequence').get(c, u, 'account.bank.statement.line.global'), + 'code': lambda s,c,u,ctx={}: s.pool.get('ir.sequence').next_by_code(c, u, 'account.bank.statement.line.global'), 'name': '/', } _sql_constraints = [ diff --git a/addons/account_payment/account_payment.py b/addons/account_payment/account_payment.py index de72960a9c6..e5dbbd1b8cb 100644 --- a/addons/account_payment/account_payment.py +++ b/addons/account_payment/account_payment.py @@ -113,7 +113,7 @@ class payment_order(osv.osv): 'state': 'draft', 'date_prefered': 'due', 'date_created': lambda *a: time.strftime('%Y-%m-%d'), - 'reference': lambda self,cr,uid,context: self.pool.get('ir.sequence').get(cr, uid, 'payment.order'), + 'reference': lambda self,cr,uid,context: self.pool.get('ir.sequence').next_by_code(cr, uid, 'payment.order'), } def set_to_draft(self, cr, uid, ids, *args): @@ -126,7 +126,7 @@ class payment_order(osv.osv): for order in self.read(cr, uid, ids, ['reference']): if not order['reference']: - reference = ir_seq_obj.get(cr, uid, 'payment.order') + reference = ir_seq_obj.next_by_code(cr, uid, 'payment.order') self.write(cr, uid, order['id'], {'reference':reference}) return True @@ -322,7 +322,7 @@ class payment_line(osv.osv): } _defaults = { 'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence' - ).get(cursor, user, 'payment.line'), + ).next_by_code(cursor, user, 'payment.line'), 'state': 'normal', 'currency': _get_currency, 'company_currency': _get_currency, diff --git a/addons/analytic/models/analytic.py b/addons/analytic/models/analytic.py index 6d01a68c9a3..6d7423d1adf 100644 --- a/addons/analytic/models/analytic.py +++ b/addons/analytic/models/analytic.py @@ -251,7 +251,7 @@ class account_analytic_account(osv.osv): _defaults = { 'type': 'normal', 'company_id': _default_company, - 'code' : lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account'), + 'code' : lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'account.analytic.account'), 'state': 'open', 'user_id': lambda self, cr, uid, ctx: uid, 'partner_id': lambda self, cr, uid, ctx: ctx.get('partner_id', False), diff --git a/addons/hr_payroll/hr_payroll.py b/addons/hr_payroll/hr_payroll.py index 397938f3442..cda5cc657c0 100644 --- a/addons/hr_payroll/hr_payroll.py +++ b/addons/hr_payroll/hr_payroll.py @@ -377,7 +377,7 @@ class hr_payslip(osv.osv): slip_line_pool = self.pool.get('hr.payslip.line') sequence_obj = self.pool.get('ir.sequence') for payslip in self.browse(cr, uid, ids, context=context): - number = payslip.number or sequence_obj.get(cr, uid, 'salary.slip') + number = payslip.number or sequence_obj.next_by_code(cr, uid, 'salary.slip') #delete old payslip lines old_slipline_ids = slip_line_pool.search(cr, uid, [('slip_id', '=', payslip.id)], context=context) # old_slipline_ids diff --git a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py index 8fa11545dee..32a6d1c0125 100644 --- a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py +++ b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py @@ -174,7 +174,7 @@ class partner_vat_list(osv.osv_memory): obj_users = self.pool.get('res.users') obj_partner = self.pool.get('res.partner') obj_model_data = self.pool.get('ir.model.data') - seq_declarantnum = obj_sequence.get(cr, uid, 'declarantnum') + seq_declarantnum = obj_sequence.next_by_code(cr, uid, 'declarantnum') obj_cmpny = obj_users.browse(cr, uid, uid, context=context).company_id company_vat = obj_cmpny.partner_id.vat @@ -184,7 +184,7 @@ class partner_vat_list(osv.osv_memory): company_vat = company_vat.replace(' ','').upper() SenderId = company_vat[2:] issued_by = company_vat[:2] - seq_declarantnum = obj_sequence.get(cr, uid, 'declarantnum') + seq_declarantnum = obj_sequence.next_by_code(cr, uid, 'declarantnum') dnum = company_vat[2:] + seq_declarantnum[-4:] street = city = country = '' addr = obj_partner.address_get(cr, uid, [obj_cmpny.partner_id.id], ['invoice']) diff --git a/addons/l10n_be/wizard/l10n_be_vat_intra.py b/addons/l10n_be/wizard/l10n_be_vat_intra.py index 386aa0906fd..f937632cb51 100644 --- a/addons/l10n_be/wizard/l10n_be_vat_intra.py +++ b/addons/l10n_be/wizard/l10n_be_vat_intra.py @@ -123,7 +123,7 @@ class partner_vat_intra(osv.osv_memory): if not p_id_list: raise osv.except_osv(_('Insufficient Data!'),_('No partner has a VAT number associated with him.')) - seq_declarantnum = obj_sequence.get(cr, uid, 'declarantnum') + seq_declarantnum = obj_sequence.next_by_code(cr, uid, 'declarantnum') dnum = company_vat[2:] + seq_declarantnum[-4:] addr = obj_partner.address_get(cr, uid, [data_company.partner_id.id], ['invoice']) diff --git a/addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py b/addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py index 0af3535bfd0..1c2402153d0 100644 --- a/addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py +++ b/addons/l10n_in_hr_payroll/l10n_in_hr_payroll.py @@ -132,7 +132,7 @@ class payroll_advice(osv.osv): raise osv.except_osv(_('Error!'), _('You can not confirm Payment advice without advice lines.')) advice_date = datetime.strptime(advice.date, DATETIME_FORMAT) advice_year = advice_date.strftime('%m') + '-' + advice_date.strftime('%Y') - number = seq_obj.get(cr, uid, 'payment.advice') + number = seq_obj.next_by_code(cr, uid, 'payment.advice') sequence_num = 'PAY' + '/' + advice_year + '/' + number self.write(cr, uid, [advice.id], {'number': sequence_num, 'state': 'confirm'}, context=context) return True diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 914cfc376a6..9b3d832c541 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -585,7 +585,7 @@ class mrp_production(osv.osv): 'date_planned': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'product_qty': lambda *a: 1.0, 'user_id': lambda self, cr, uid, c: uid, - 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'mrp.production') or '/', + 'name': lambda x, y, z, c: x.pool.get('ir.sequence').next_by_code(y, z, 'mrp.production') or '/', 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.production', context=c), 'location_src_id': _src_id_default, 'location_dest_id': _dest_id_default diff --git a/addons/mrp/security/ir.model.access.csv b/addons/mrp/security/ir.model.access.csv index 7ed5ff7596e..fc3b228bb48 100644 --- a/addons/mrp/security/ir.model.access.csv +++ b/addons/mrp/security/ir.model.access.csv @@ -28,7 +28,6 @@ access_mrp_production_stock_worker,mrp.production stock_worker,model_mrp_product access_report_workcenter_load,report.workcenter.load,model_report_workcenter_load,mrp.group_mrp_manager,1,1,1,1 access_report_mrp_inout,report.mrp.inout,model_report_mrp_inout,mrp.group_mrp_manager,1,1,1,1 access_ir_property_manager,ir.property manager,base.model_ir_property,mrp.group_mrp_manager,1,1,1,1 -access_account_sequence_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,mrp.group_mrp_user,1,1,1,1 access_product_product_user,product.product user,product.model_product_product,mrp.group_mrp_user,1,0,0,0 access_product_template_user,product.template user,product.model_product_template,mrp.group_mrp_user,1,0,0,0 access_product_uom_user,product.uom user,product.model_product_uom,mrp.group_mrp_user,1,0,0,0 @@ -42,14 +41,12 @@ access_resource_calendar_attendance_manager,mrp.resource.calendar.attendance.man access_product_puom_categ,product.uom.categ,product.model_product_uom_categ,mrp.group_mrp_user,1,0,0,0 access_resource_resource,resource.resource,resource.model_resource_resource,mrp.group_mrp_user,1,0,0,0 access_board_board_user,mrp.board.board,board.model_board_board,mrp.group_mrp_user,1,0,0,0 -access_account_sequence_fiscalyear_manager,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,mrp.group_mrp_manager,1,0,0,0 access_product_supplierinfo_manager,product.supplierinfo user,product.model_product_supplierinfo,mrp.group_mrp_manager,1,0,0,0 access_mrp_production_manager,mrp.production manager,model_mrp_production,mrp.group_mrp_manager,1,0,0,0 access_procurement_manager,procurement.order,model_procurement_order,mrp.group_mrp_manager,1,0,0,0 access_workcenter_manager,mrp.production.workcenter.line,model_mrp_production_workcenter_line,mrp.group_mrp_manager,1,0,0,0 access_stock_move_mrp_manager,stock.move mrp_manager,stock.model_stock_move,mrp.group_mrp_manager,1,0,0,0 access_mrp_production_product_line_manager,mrp.production.product.line manager,model_mrp_production_product_line,mrp.group_mrp_manager,1,0,0,0 -access_account_sequence_fiscalyear_system,account.sequence.fiscalyear.system,account.model_account_sequence_fiscalyear,mrp.group_mrp_manager,1,0,0,0 access_stock_production_lot_user,stock.production.lot,stock.model_stock_production_lot,mrp.group_mrp_user,1,1,1,1 access_stock_warehouse_orderpoint_user,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,mrp.group_mrp_user,1,0,0,0 access_stock_picking_mrp_manager,stock.picking mrp_manager,stock.model_stock_picking,mrp.group_mrp_manager,1,0,0,0 diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py index d8c8925b24f..d80338fd024 100644 --- a/addons/mrp_repair/mrp_repair.py +++ b/addons/mrp_repair/mrp_repair.py @@ -187,7 +187,7 @@ class mrp_repair(osv.osv): _defaults = { 'state': lambda *a: 'draft', - 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'mrp.repair'), + 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'mrp.repair'), 'invoice_method': lambda *a: 'none', 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.repair', context=context), 'pricelist_id': lambda self, cr, uid, context: self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'sale')])[0], diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index 91e2cd14d09..5b67bdc9c1c 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -425,7 +425,7 @@ class pos_session(osv.osv): bank_statement_ids.append(statement_id) values.update({ - 'name': self.pool['ir.sequence'].get(cr, uid, 'pos.session'), + 'name': self.pool['ir.sequence'].next_by_code(cr, uid, 'pos.session'), 'statement_ids' : [(6, 0, bank_statement_ids)], 'config_id': config_id }) @@ -749,7 +749,7 @@ class pos_order(osv.osv): values['name'] = session.config_id.sequence_id._next() else: # fallback on any pos.order sequence - values['name'] = self.pool.get('ir.sequence').get_id(cr, uid, 'pos.order', 'code', context=context) + values['name'] = self.pool.get('ir.sequence').next_by_code(cr, uid, 'pos.order', context=context) return super(pos_order, self).create(cr, uid, values, context=context) def test_paid(self, cr, uid, ids, context=None): @@ -1322,7 +1322,7 @@ class pos_order_line(osv.osv): } _defaults = { - 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'pos.order.line'), + 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'pos.order.line'), 'qty': lambda *a: 1, 'discount': lambda *a: 0.0, 'company_id': lambda self,cr,uid,c: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id, diff --git a/addons/point_of_sale/security/ir.model.access.csv b/addons/point_of_sale/security/ir.model.access.csv index faa14f1d490..4850bf7321e 100644 --- a/addons/point_of_sale/security/ir.model.access.csv +++ b/addons/point_of_sale/security/ir.model.access.csv @@ -47,7 +47,6 @@ access_account_bank_statement_line_manager,account.bank.statement.line manager,a access_account_invoice_manager,account.invoice manager,account.model_account_invoice,group_pos_manager,1,1,1,1 access_product_product_supplierinfo_user,product.supplierinfo user,product.model_product_supplierinfo,group_pos_user,1,0,0,0 access_product_product_packaging_user,product.packaging user,product.model_product_packaging,group_pos_user,1,0,0,0 -access_account_sequence_fiscalyear_manager,account.sequence.fiscalyear manager,account.model_account_sequence_fiscalyear,group_pos_manager,1,0,0,0 access_stock_warehouse_manager,stock.warehouse manager,stock.model_stock_warehouse,group_pos_manager,1,0,0,0 access_stock_location_manager,stock.location manager,stock.model_stock_location,group_pos_manager,1,0,0,0 access_product_uom_manager,product.uom manager,product.model_product_uom,group_pos_manager,1,1,1,1 diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 12d40a39be1..12e731e2e5c 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -64,7 +64,7 @@ class procurement_group(osv.osv): 'procurement_ids': fields.one2many('procurement.order', 'group_id', 'Procurements'), } _defaults = { - 'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').get(cr, uid, 'procurement.group') or '', + 'name': lambda self, cr, uid, c: self.pool.get('ir.sequence').next_by_code(cr, uid, 'procurement.group') or '', 'move_type': lambda self, cr, uid, c: 'direct' } diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 5dd100c6905..9f3622cb811 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -326,7 +326,7 @@ class purchase_order(osv.osv): def create(self, cr, uid, vals, context=None): if vals.get('name','/')=='/': - vals['name'] = self.pool.get('ir.sequence').get(cr, uid, 'purchase.order') or '/' + vals['name'] = self.pool.get('ir.sequence').next_by_code(cr, uid, 'purchase.order') or '/' context = dict(context or {}, mail_create_nolog=True) order = super(purchase_order, self).create(cr, uid, vals, context=context) self.message_post(cr, uid, [order], body=_("RFQ created"), context=context) @@ -1358,7 +1358,7 @@ class procurement_order(osv.osv): po_line_id = po_line_obj.create(cr, SUPERUSER_ID, line_vals, context=context) linked_po_ids.append(procurement.id) else: - name = seq_obj.get(cr, uid, 'purchase.order') or _('PO: %s') % procurement.name + name = seq_obj.next_by_code(cr, uid, 'purchase.order') or _('PO: %s') % procurement.name po_vals = { 'name': name, 'origin': procurement.origin, diff --git a/addons/purchase/security/ir.model.access.csv b/addons/purchase/security/ir.model.access.csv index 74a3e44ae05..b6f63a9bd46 100644 --- a/addons/purchase/security/ir.model.access.csv +++ b/addons/purchase/security/ir.model.access.csv @@ -28,7 +28,6 @@ access_account_invoice_purchase_manager,account_invoice purchase manager,account access_account_invoice_line_purchase_manager,account_invoice.line purchase manager,account.model_account_invoice_line,group_purchase_manager,1,0,0,0 access_account_invoice_tax_purchase,account_invoice.tax purchase,account.model_account_invoice_tax,group_purchase_user,1,1,1,1 access_account_fiscal_position_purchase_user,account.fiscal.position purchase,account.model_account_fiscal_position,group_purchase_user,1,0,0,0 -access_account_sequence_fiscalyear_purchase_user,account.sequence.fiscalyear purchase,account.model_account_sequence_fiscalyear,group_purchase_user,1,1,1,1 access_res_partner_purchase_user,res.partner purchase,base.model_res_partner,group_purchase_user,1,0,0,0 access_account_journal_period,account.journal.period,account.model_account_journal_period,group_purchase_user,1,1,1,0 access_account_journal,account.journal,account.model_account_journal,group_purchase_user,1,0,0,0 diff --git a/addons/purchase_requisition/purchase_requisition.py b/addons/purchase_requisition/purchase_requisition.py index 5af69a65a99..cfedba1a6b3 100644 --- a/addons/purchase_requisition/purchase_requisition.py +++ b/addons/purchase_requisition/purchase_requisition.py @@ -72,7 +72,7 @@ class purchase_requisition(osv.osv): 'exclusive': 'multiple', 'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'purchase.requisition', context=c), 'user_id': lambda self, cr, uid, c: self.pool.get('res.users').browse(cr, uid, uid, c).id, - 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'purchase.order.requisition'), + 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'purchase.order.requisition'), 'picking_type_id': _get_picking_in, } diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 2cbc975ae4c..c87a880891a 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -349,7 +349,7 @@ class sale_order(osv.osv): if context is None: context = {} if vals.get('name', '/') == '/': - vals['name'] = self.pool.get('ir.sequence').get(cr, uid, 'sale.order') or '/' + vals['name'] = self.pool.get('ir.sequence').next_by_code(cr, uid, 'sale.order') or '/' if vals.get('partner_id') and any(f not in vals for f in ['partner_invoice_id', 'partner_shipping_id', 'pricelist_id', 'fiscal_position']): defaults = self.onchange_partner_id(cr, uid, [], vals['partner_id'], context=context)['value'] if not vals.get('fiscal_position') and vals.get('partner_shipping_id'): diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 75def9b40d1..d0293f159d6 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -681,7 +681,7 @@ class stock_picking(osv.osv): if ('name' not in vals) or (vals.get('name') in ('/', False)): ptype_id = vals.get('picking_type_id', context.get('default_picking_type_id', False)) sequence_id = self.pool.get('stock.picking.type').browse(cr, user, ptype_id, context=context).sequence_id.id - vals['name'] = self.pool.get('ir.sequence').get_id(cr, user, sequence_id, 'id', context=context) + vals['name'] = self.pool.get('ir.sequence').next_by_id(cr, user, sequence_id, context=context) return super(stock_picking, self).create(cr, user, vals, context) def _state_get(self, cr, uid, ids, field_name, arg, context=None): @@ -1486,7 +1486,7 @@ class stock_production_lot(osv.osv): 'create_date': fields.datetime('Creation Date'), } _defaults = { - 'name': lambda x, y, z, c: x.pool.get('ir.sequence').get(y, z, 'stock.lot.serial'), + 'name': lambda x, y, z, c: x.pool.get('ir.sequence').next_by_code(y, z, 'stock.lot.serial'), 'product_id': lambda x, y, z, c: c.get('product_id', False), } _sql_constraints = [ @@ -3692,7 +3692,7 @@ class stock_package(osv.osv): }, readonly=True, select=True), } _defaults = { - 'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').get(cr, uid, 'stock.quant.package') or _('Unknown Pack') + 'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').next_by_code(cr, uid, 'stock.quant.package') or _('Unknown Pack') } def _check_location_constraint(self, cr, uid, packs, context=None): @@ -4087,7 +4087,7 @@ class stock_warehouse_orderpoint(osv.osv): 'active': lambda *a: 1, 'logic': lambda *a: 'max', 'qty_multiple': lambda *a: 1, - 'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint') or '', + 'name': lambda self, cr, uid, context: self.pool.get('ir.sequence').next_by_code(cr, uid, 'stock.orderpoint') or '', 'product_uom': lambda self, cr, uid, context: context.get('product_uom', False), 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.warehouse.orderpoint', context=context) } diff --git a/addons/stock_landed_costs/stock_landed_costs.py b/addons/stock_landed_costs/stock_landed_costs.py index ad729377fb2..515fd2c1feb 100644 --- a/addons/stock_landed_costs/stock_landed_costs.py +++ b/addons/stock_landed_costs/stock_landed_costs.py @@ -93,7 +93,7 @@ class stock_landed_cost(osv.osv): } _defaults = { - 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'stock.landed.cost'), + 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').next_by_code(cr, uid, 'stock.landed.cost'), 'state': 'draft', 'date': fields.date.context_today, } diff --git a/addons/stock_picking_wave/stock_picking_wave.py b/addons/stock_picking_wave/stock_picking_wave.py index 48779f6882c..86809a8d58f 100644 --- a/addons/stock_picking_wave/stock_picking_wave.py +++ b/addons/stock_picking_wave/stock_picking_wave.py @@ -44,7 +44,7 @@ class stock_picking_wave(osv.osv): def create(self, cr, uid, vals, context=None): if vals.get('name', '/') == '/': - vals['name'] = self.pool.get('ir.sequence').get(cr, uid, 'picking.wave') or '/' + vals['name'] = self.pool.get('ir.sequence').next_by_code(cr, uid, 'picking.wave') or '/' return super(stock_picking_wave, self).create(cr, uid, vals, context=context) def done(self, cr, uid, ids, context=None): diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py index d2296526394..36970310d92 100644 --- a/openerp/addons/base/ir/ir_sequence.py +++ b/openerp/addons/base/ir/ir_sequence.py @@ -18,33 +18,35 @@ # along with this program. If not, see . # ############################################################################## - import logging import time -import openerp -from openerp.osv import osv -from openerp.tools.translate import _ +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta +from openerp import _, api, fields, models +from openerp.exceptions import Warning _logger = logging.getLogger(__name__) -class ir_sequence_type(openerp.osv.osv.osv): + +class ir_sequence_type(models.Model): _name = 'ir.sequence.type' _order = 'name' - _columns = { - 'name': openerp.osv.fields.char('Name', required=True), - 'code': openerp.osv.fields.char('Code', size=32, required=True), - } + + name = fields.Char(required=True) + code = fields.Char(size=32, required=True) _sql_constraints = [ ('code_unique', 'unique(code)', '`code` must be unique.'), ] -def _code_get(self, cr, uid, context=None): - cr.execute('select code, name from ir_sequence_type') - return cr.fetchall() -class ir_sequence(openerp.osv.osv.osv): +def _code_get(self): + self.env.cr.execute('select code, name from ir_sequence_type') + return self.env.cr.fetchall() + + +class ir_sequence(models.Model): """ Sequence model. The sequence model allows to define and use so-called sequence objects. @@ -54,172 +56,171 @@ class ir_sequence(openerp.osv.osv.osv): """ _name = 'ir.sequence' _order = 'name' - - def _get_number_next_actual(self, cr, user, ids, field_name, arg, context=None): + + def _get_number_next_actual(self): '''Return number from ir_sequence row when no_gap implementation, and number from postgres sequence when standard implementation.''' - res = dict.fromkeys(ids) - for element in self.browse(cr, user, ids, context=context): - if element.implementation != 'standard': - res[element.id] = element.number_next + res = {} + for element in self: + if element.implementation != 'standard': + element.number_next_actual = element.number_next else: - # get number from postgres sequence. Cannot use - # currval, because that might give an error when + # get number from postgres sequence. Cannot use currval, because that might give an error when # not having used nextval before. - statement = ( - "SELECT last_value, increment_by, is_called" - " FROM ir_sequence_%03d" - % element.id) - cr.execute(statement) - (last_value, increment_by, is_called) = cr.fetchone() + query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d" % element.id + self.env.cr.execute(query) + (last_value, increment_by, is_called) = self.env.cr.fetchone() if is_called: - res[element.id] = last_value + increment_by + element.number_next_actual = last_value + increment_by else: - res[element.id] = last_value - return res + element.number_next_actual = last_value - def _set_number_next_actual(self, cr, uid, id, name, value, args=None, context=None): - return self.write(cr, uid, id, {'number_next': value or 0}, context=context) + def _set_number_next_actual(self): + for record in self: + record.write({'number_next': record.number_next_actual or 0}) - - _columns = { - 'name': openerp.osv.fields.char('Name', size=64, required=True), - 'code': openerp.osv.fields.selection(_code_get, 'Sequence Type', size=64), - 'implementation': openerp.osv.fields.selection( # TODO update the view - [('standard', 'Standard'), ('no_gap', 'No gap')], - 'Implementation', required=True, - help="Two sequence object implementations are offered: Standard " - "and 'No gap'. The later is slower than the former but forbids any" - " gap in the sequence (while they are possible in the former)."), - 'active': openerp.osv.fields.boolean('Active'), - 'prefix': openerp.osv.fields.char('Prefix', help="Prefix value of the record for the sequence"), - 'suffix': openerp.osv.fields.char('Suffix', help="Suffix value of the record for the sequence"), - 'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"), - 'number_next_actual': openerp.osv.fields.function(_get_number_next_actual, fnct_inv=_set_number_next_actual, type='integer', required=True, string='Next Number', help='Next number that will be used. This number can be incremented frequently so the displayed value might already be obsolete'), - 'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"), - 'padding' : openerp.osv.fields.integer('Number Padding', required=True, help="Odoo will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."), - 'company_id': openerp.osv.fields.many2one('res.company', 'Company'), - } - _defaults = { - 'implementation': 'standard', - 'active': True, - 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.sequence', context=c), - 'number_increment': 1, - 'number_next': 1, - 'number_next_actual': 1, - 'padding' : 0, - } + name = fields.Char(size=64, required=True) + code = fields.Selection(_code_get, 'Sequence Type', size=64) + implementation = fields.Selection( + [('standard', 'Standard'), ('no_gap', 'No gap')], + 'Implementation', required=True, default='standard', + help="Two sequence object implementations are offered: Standard " + "and 'No gap'. The later is slower than the former but forbids any" + " gap in the sequence (while they are possible in the former).") + active = fields.Boolean(default=True) + prefix = fields.Char(help="Prefix value of the record for the sequence") + suffix = fields.Char(help="Suffix value of the record for the sequence") + number_next = fields.Integer('Next Number', required=True, default=1, help="Next number of this sequence") + number_next_actual = fields.Integer(compute='_get_number_next_actual', inverse='_set_number_next_actual', + required=True, string='Next Number', default=1, + help="Next number that will be used. This number can be incremented " + "frequently so the displayed value might already be obsolete") + number_increment = fields.Integer('Increment Number', required=True, default=1, + help="The next number of the sequence will be incremented by this number") + padding = fields.Integer('Number Padding', required=True, default=0, + help="Odoo will automatically adds some '0' on the left of the " + "'Next Number' to get the required padding size.") + company_id = fields.Many2one('res.company', 'Company', + default=lambda s: s.env['res.company']._company_default_get('ir.sequence')) + use_date_range = fields.Boolean('Use subsequences per date_range') + date_range_ids = fields.One2many('ir.sequence.date_range', 'sequence_main_id', 'Subsequences') def init(self, cr): - return # Don't do the following index yet. - # CONSTRAINT/UNIQUE INDEX on (code, company_id) + return # Don't do the following index yet. + # CONSTRAINT/UNIQUE INDEX on (code, company_id) # /!\ The unique constraint 'unique_name_company_id' is not sufficient, because SQL92 # only support field names in constraint definitions, and we need a function here: # we need to special-case company_id to treat all NULL company_id as equal, otherwise # we would allow duplicate (code, NULL) ir_sequences. - cr.execute(""" + self.env.cr.execute(""" SELECT indexname FROM pg_indexes WHERE indexname = 'ir_sequence_unique_code_company_id_idx'""") - if not cr.fetchone(): - cr.execute(""" + if not self.env.cr.fetchone(): + self.env.cr.execute(""" CREATE UNIQUE INDEX ir_sequence_unique_code_company_id_idx ON ir_sequence (code, (COALESCE(company_id,-1)))""") - def _create_sequence(self, cr, id, number_increment, number_next): + def _create_sequence(self, number_increment, number_next, seq_date_id=False): """ Create a PostreSQL sequence. There is no access rights check. """ if number_increment == 0: - raise osv.except_osv(_('Warning!'),_("Increment number must not be zero.")) - assert isinstance(id, (int, long)) - sql = "CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s" % id - cr.execute(sql, (number_increment, number_next)) + raise Warning(_('Increment number must not be zero.')) + if seq_date_id: + sql = "CREATE SEQUENCE ir_sequence_%03d_%03d INCREMENT BY %%s START WITH %%s" % (self.id, seq_date_id.id) + else: + sql = "CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %%s START WITH %%s" % self.id + self.env.cr.execute(sql, (number_increment, number_next)) - def _drop_sequence(self, cr, ids): + def _drop_sequence(self): """ Drop the PostreSQL sequence if it exists. There is no access rights check. """ - - ids = ids if isinstance(ids, (list, tuple)) else [ids] - assert all(isinstance(i, (int, long)) for i in ids), \ - "Only ids in (int, long) allowed." - names = ','.join('ir_sequence_%03d' % i for i in ids) + names = [] + for seq in self: + for seq_date_id in seq.date_range_ids: + names.append('ir_sequence_%03d_%03d' % (seq.id, seq_date_id)) + names.append('ir_sequence_%03d' % seq.id) + names = ','.join(names) # RESTRICT is the default; it prevents dropping the sequence if an # object depends on it. - cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names) + self.env.cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names) - def _alter_sequence(self, cr, id, number_increment, number_next=None): + def _alter_sequence(self, number_increment=None, number_next=None, seq_date_id=False): """ Alter a PostreSQL sequence. There is no access rights check. """ if number_increment == 0: - raise osv.except_osv(_('Warning!'),_("Increment number must not be zero.")) - assert isinstance(id, (int, long)) - seq_name = 'ir_sequence_%03d' % (id,) - cr.execute("SELECT relname FROM pg_class WHERE relkind = %s AND relname=%s", ('S', seq_name)) - if not cr.fetchone(): + raise Warning(_("Increment number must not be zero.")) + if seq_date_id: + seq_name = 'ir_sequence_%03d_%03d' % (self.id, seq_date_id.id) + else: + seq_name = 'ir_sequence_%03d' % (self.id) + self.env.cr.execute("SELECT relname FROM pg_class WHERE relkind = %s AND relname=%s", ('S', seq_name)) + if not self.env.cr.fetchone(): # sequence is not created yet, we're inside create() so ignore it, will be set later return - statement = "ALTER SEQUENCE %s INCREMENT BY %d" % (seq_name, number_increment) + statement = "ALTER SEQUENCE %s" % (seq_name, ) + if number_increment is not None: + statement += " INCREMENT BY %d" % (number_increment, ) if number_next is not None: statement += " RESTART WITH %d" % (number_next, ) - cr.execute(statement) + self.env.cr.execute(statement) - def create(self, cr, uid, values, context=None): + @api.model + def create(self, values): """ Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used. """ - values = self._add_missing_default_values(cr, uid, values, context) - values['id'] = super(ir_sequence, self).create(cr, uid, values, context) + values = self._add_missing_default_values(values) + seq = super(ir_sequence, self).create(values) if values['implementation'] == 'standard': - self._create_sequence(cr, values['id'], values['number_increment'], values['number_next']) - return values['id'] + seq._create_sequence(values['number_increment'], values['number_next']) + return seq - def unlink(self, cr, uid, ids, context=None): - super(ir_sequence, self).unlink(cr, uid, ids, context) - self._drop_sequence(cr, ids) - return True + @api.multi + def unlink(self): + self._drop_sequence() + return super(ir_sequence, self).unlink() - def write(self, cr, uid, ids, values, context=None): - if not isinstance(ids, (list, tuple)): - ids = [ids] + @api.multi + def write(self, values): new_implementation = values.get('implementation') - rows = self.read(cr, uid, ids, ['implementation', 'number_increment', 'number_next'], context) - super(ir_sequence, self).write(cr, uid, ids, values, context) - for row in rows: + for seq in self: # 4 cases: we test the previous impl. against the new one. - i = values.get('number_increment', row['number_increment']) - n = values.get('number_next', row['number_next']) - if row['implementation'] == 'standard': + i = values.get('number_increment', seq.number_increment) + n = values.get('number_next', seq.number_next) + if seq.implementation == 'standard': if new_implementation in ('standard', None): # Implementation has NOT changed. # Only change sequence if really requested. - if row['number_next'] != n: - self._alter_sequence(cr, row['id'], i, n) - else: - # Just in case only increment changed - self._alter_sequence(cr, row['id'], i) + if seq.number_next != n: + seq._alter_sequence(number_next=n) + if seq.number_increment != i: + seq._alter_sequence(number_increment=i) + for seq_date_id in seq.date_range_ids: + seq._alter_sequence(number_increment=i, seq_date_id=seq_date_id) else: - self._drop_sequence(cr, row['id']) + seq._drop_sequence() else: if new_implementation in ('no_gap', None): pass else: - self._create_sequence(cr, row['id'], i, n) + seq._create_sequence(i, n) - return True + return super(ir_sequence, self).write(values) def _interpolate(self, s, d): if s: return s % d - return '' + return '' def _interpolation_dict(self): - t = time.localtime() # Actually, the server is always in UTC. + t = time.localtime() # Actually, the server is always in UTC. return { 'year': time.strftime('%Y', t), 'month': time.strftime('%m', t), @@ -234,40 +235,80 @@ class ir_sequence(openerp.osv.osv.osv): 'sec': time.strftime('%S', t), } - def _next(self, cr, uid, ids, context=None): - if not ids: - return False - if context is None: - context = {} - force_company = context.get('force_company') - if not force_company: - force_company = self.pool.get('res.users').browse(cr, uid, uid).company_id.id - sequences = self.read(cr, uid, ids, ['name','company_id','implementation','number_next','prefix','suffix','padding']) - preferred_sequences = [s for s in sequences if s['company_id'] and s['company_id'][0] == force_company ] - seq = preferred_sequences[0] if preferred_sequences else sequences[0] - if seq['implementation'] == 'standard': - cr.execute("SELECT nextval('ir_sequence_%03d')" % seq['id']) - seq['number_next'] = cr.fetchone() + def _next_do(self, seq_date_id=False): + cr = self.env.cr + if self.implementation == 'standard': + if seq_date_id: + sql = "SELECT nextval('ir_sequence_%03d_%03d')" % (self.id, seq_date_id.id) + else: + sql = "SELECT nextval('ir_sequence_%03d')" % self.id + cr.execute(sql) + number_next = cr.fetchone() else: - cr.execute("SELECT number_next FROM ir_sequence WHERE id=%s FOR UPDATE NOWAIT", (seq['id'],)) - cr.execute("UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s ", (seq['id'],)) - self.invalidate_cache(cr, uid, ['number_next'], [seq['id']], context=context) + if seq_date_id: + model_name = 'ir_sequence_date_range' + model_obj = self.env['ir.sequence.date_range'] + id = seq_date_id + else: + model_name = 'ir_sequence' + model_obj = self + id = self + number_next = id.number_next + cr.execute("SELECT number_next FROM %s WHERE id=%s FOR UPDATE NOWAIT" % (model_name, id.id)) + cr.execute("UPDATE %s SET number_next=number_next+%s WHERE id=%s " % (model_name, self.number_increment, id.id)) + model_obj.invalidate_cache(['number_next'], [id.id]) d = self._interpolation_dict() try: - interpolated_prefix = self._interpolate(seq['prefix'], d) - interpolated_suffix = self._interpolate(seq['suffix'], d) + interpolated_prefix = self._interpolate(self.prefix, d) + interpolated_suffix = self._interpolate(self.suffix, d) except ValueError: - raise osv.except_osv(_('Warning'), _('Invalid prefix or suffix for sequence \'%s\'') % (seq.get('name'))) - return interpolated_prefix + '%%0%sd' % seq['padding'] % seq['number_next'] + interpolated_suffix + raise Warning(_('Invalid prefix or suffix for sequence \'%s\'') % (self.get('name'))) + return interpolated_prefix + '%%0%sd' % self.padding % number_next + interpolated_suffix - def next_by_id(self, cr, uid, sequence_id, context=None): + def _create_date_range_seq(self, date): + year = datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT).strftime('%Y') + date_from = '{}-01-01'.format(year) + date_to = '{}-12-31'.format(year) + for line in self.date_range_ids: + if date < line.date_from < date_to: + date_to = datetime.strptime(line.date_from, '%Y-%m-%d') + timedelta(days=-1) + date_to = date_to.strftime('%Y-%m-%d') + elif date_from < line.date_to < date: + date_from = datetime.strptime(line.date_to, '%Y-%m-%d') + timedelta(days=1) + date_from = date_from.strftime('%Y-%m-%d') + seq_date_id = self.env['ir.sequence.date_range'].sudo().create({ + 'date_from': date_from, + 'date_to': date_to, + 'sequence_main_id': self.id, + }) + if self.implementation == 'standard': + self._create_sequence(self.number_increment, 1, seq_date_id=seq_date_id) + return seq_date_id + + def _next(self): + """ Returns the next number in the preferred sequence in all the ones given in self. + """ + if self.use_date_range: + dt = self.env.context.get('date', fields.Date.today()) + seq_date_id = False + for line in self.date_range_ids: + if line.date_from <= dt <= line.date_to: + seq_date_id = line + break + if not seq_date_id: + seq_date_id = self._create_date_range_seq(dt) + return self._next_do(seq_date_id=seq_date_id) + else: + return self._next_do() + + @api.multi + def next_by_id(self): """ Draw an interpolated string using the specified sequence.""" - self.check_access_rights(cr, uid, 'read') - company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) + [False] - ids = self.search(cr, uid, ['&',('id','=', sequence_id),('company_id','in',company_ids)]) - return self._next(cr, uid, ids, context) + self.check_access_rights('read') + return self._next() - def next_by_code(self, cr, uid, sequence_code, context=None): + @api.model + def next_by_code(self, sequence_code): """ Draw an interpolated string using a sequence with the requested code. If several sequences with the correct code are available to the user (multi-company cases), the one from the user's current company will @@ -277,35 +318,86 @@ class ir_sequence(openerp.osv.osv.osv): ``force_company`` key with the ID of the company to use instead of the user's current company for the sequence selection. A matching sequence for that - specific company will get higher priority. + specific company will get higher priority. """ - self.check_access_rights(cr, uid, 'read') - company_ids = self.pool.get('res.company').search(cr, uid, [], context=context) + [False] - ids = self.search(cr, uid, ['&', ('code', '=', sequence_code), ('company_id', 'in', company_ids)]) - return self._next(cr, uid, ids, context) + self.check_access_rights('read') + company_ids = self.env['res.company'].search([]).ids + [False] + seq_ids = self.search(['&', ('code', '=', sequence_code), ('company_id', 'in', company_ids)]) + if not seq_ids: + return False + force_company = self.env.context.get('force_company') + if not force_company: + self.env.user.company_id + preferred_sequences = [s for s in seq_ids if s.company_id and s.company_id == force_company] + seq_id = preferred_sequences[0] if preferred_sequences else seq_ids[0] + return seq_id._next() - def get_id(self, cr, uid, sequence_code_or_id, code_or_id='id', context=None): + @api.model + def get_id(self, sequence_code_or_id, code_or_id='id'): """ Draw an interpolated string using the specified sequence. The sequence to use is specified by the ``sequence_code_or_id`` argument, which can be a code or an id (as controlled by the ``code_or_id`` argument. This method is deprecated. """ - # TODO: bump up to warning after 6.1 release - _logger.debug("ir_sequence.get() and ir_sequence.get_id() are deprecated. " - "Please use ir_sequence.next_by_code() or ir_sequence.next_by_id().") + _logger.warning("ir_sequence.get() and ir_sequence.get_id() are deprecated. " + "Please use ir_sequence.next_by_code() or ir_sequence.next_by_id().") if code_or_id == 'id': - return self.next_by_id(cr, uid, sequence_code_or_id, context) + return self.browse(sequence_code_or_id).next_by_id() else: - return self.next_by_code(cr, uid, sequence_code_or_id, context) + return self.next_by_code(sequence_code_or_id) - def get(self, cr, uid, code, context=None): + @api.model + def get(self, code): """ Draw an interpolated string using the specified sequence. The sequence to use is specified by its code. This method is deprecated. """ - return self.get_id(cr, uid, code, 'code', context) + return self.get_id(code, 'code') +class ir_sequence_date_range(models.Model): + _name = 'ir.sequence.date_range' + _rec_name = "sequence_main_id" + + def _get_number_next_actual(self): + '''Return number from ir_sequence row when no_gap implementation, + and number from postgres sequence when standard implementation.''' + for element in self: + if element.sequence_main_id.implementation != 'standard': + element.number_next_actual = element.number_next + else: + # get number from postgres sequence. Cannot use currval, because that might give an error when + # not having used nextval before. + query = "SELECT last_value, increment_by, is_called FROM ir_sequence_%03d_%03d" % (element.sequence_main_id, element.id) + self.env.cr.execute(query) + (last_value, increment_by, is_called) = self.env.cr.fetchone() + if is_called: + element.number_next_actual = last_value + increment_by + else: + element.number_next_actual = last_value + + def _set_number_next_actual(self): + for record in self: + record.write({'number_next': record.number_next_actual or 0}) + + date_from = fields.Date('From', required=True) + date_to = fields.Date('To', required=True) + sequence_main_id = fields.Many2one("ir.sequence", 'Main Sequence', required=True, ondelete='cascade') + number_next = fields.Integer('Next Number', required=True, default=1, help="Next number of this sequence") + number_next_actual = fields.Integer(compute='_get_number_next_actual', inverse='_set_number_next_actual', + required=True, string='Next Number', default=1, + help="Next number that will be used. This number can be incremented " + "frequently so the displayed value might already be obsolete") + + @api.multi + def write(self, values): + res = super(ir_sequence_date_range, self).write(values) + for seq_date_id in self: + if seq_date_id.sequence_main_id.implementation == 'standard': + if values.get('number_next'): + seq_date_id.sequence_main_id._alter_sequence(number_next=values.get('number_next'), seq_date_id=seq_date_id) + return res + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_sequence_view.xml b/openerp/addons/base/ir/ir_sequence_view.xml index bf6b99b7c4a..213ef30424f 100644 --- a/openerp/addons/base/ir/ir_sequence_view.xml +++ b/openerp/addons/base/ir/ir_sequence_view.xml @@ -20,9 +20,17 @@ - + + + + + + + + +