def _update_models(self, cr, models={}): if not models: checklist_ids = self.search(cr, 1, []) models = dict([(checklist['model_id'][0], {'checklist_id': checklist['id'], 'active_field': checklist['active_field']}) for checklist in self.read(cr, 1, checklist_ids, ['model_id', 'active_field'])]) for model in self.pool.get('ir.model').read(cr, 1, models.keys(), ['model']): if self.pool.get(model['model']): model_columns = self.pool.get(model['model'])._columns checklist_id = models[model['id']] and models[model['id']].get('checklist_id', False) if checklist_id: model_columns.update({ 'checklist_task_instance_ids': fields.function(self._get_checklist_task_instances, type='one2many', relation='checklist.task.instance', string='Checklist Task Instances', store=False), 'total_progress_rate': fields.float('Progress Rate', digits=(16, 2)), }) columns_to_add = {'total_progress_rate': 'NUMERIC(16,2)'} if models[model['id']].get('active_field', False): if 'active' not in model_columns or model_columns['active']._type != 'boolean': model_columns.update({'active': fields.boolean('Active')}) model_columns.update({'total_progress_rate_mandatory': fields.float('Mandatory Progress Rate', digits=(16, 2))}) columns_to_add.update({'active': 'BOOLEAN', 'total_progress_rate_mandatory': 'NUMERIC(16,2)'}) for column in columns_to_add: cr.execute("""SELECT c.relname FROM pg_class c, pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid""", (model['model'].replace('.', '_'), column)) if not cr.rowcount: cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (model['model'].replace('.', '_'), column, columns_to_add[column])) cr.commit() else: if 'checklist_task_instance_ids' in model_columns: del model_columns['checklist_task_instance_ids'] if 'total_progress_rate' in model_columns: del model_columns['total_progress_rate'] return self._update_checklists_cache(cr)
def __init__(self, pool, cr): """ Dynamically add columns.""" super(report_prompt_class, self).__init__(pool, cr) for counter in range(0, MAX_PARAMS): field_name = PARAM_XXX_STRING_VALUE % counter self._columns[field_name] = fields.char('String Value', size=64) field_name = PARAM_XXX_BOOLEAN_VALUE % counter self._columns[field_name] = fields.boolean('Boolean Value') field_name = PARAM_XXX_INTEGER_VALUE % counter self._columns[field_name] = fields.integer('Integer Value') field_name = PARAM_XXX_NUMBER_VALUE % counter self._columns[field_name] = fields.float('Number Value') field_name = PARAM_XXX_DATE_VALUE % counter self._columns[field_name] = fields.date('Date Value') field_name = PARAM_XXX_TIME_VALUE % counter self._columns[field_name] = fields.datetime('Time Value') self.paramfile = False
def __init__(self, pool, cr): """ Dynamically add columns.""" super(report_prompt_class, self).__init__(pool, cr) for counter in range(0, MAX_PARAMS): field_name = PARAM_XXX_STRING_VALUE % counter self._columns[field_name] = fields.char('String Value', size=64) field_name = PARAM_XXX_BOOLEAN_VALUE % counter self._columns[field_name] = fields.boolean('Boolean Value') field_name = PARAM_XXX_INTEGER_VALUE % counter self._columns[field_name] = fields.integer('Integer Value') field_name = PARAM_XXX_NUMBER_VALUE % counter self._columns[field_name] = fields.float('Number Value') field_name = PARAM_XXX_DATE_VALUE % counter self._columns[field_name] = fields.date('Date Value') field_name = PARAM_XXX_TIME_VALUE % counter self._columns[field_name] = fields.datetime('Time Value') field_name = PARAM_XXX_2M_VALUE % counter self._columns[field_name] = fields.function(self._multi_select_values.im_func, arg={"entry_num": counter}, fnct_inv=self._multi_select_values_store.im_func, fnct_inv_arg={"entry_num": counter}, method=False, type='many2many', relation='ir.actions.report.multivalues.promptwizard', string='Multi-Select')
STATE_SELECTION = [ ('draft', 'New'), ('open', 'Accepted'), ('cancel', 'Refused'), ('close', 'Done') ] _name='devil.formulas' _description='Formula Calculation' _columns={ 'name': fields.char('Transaction Code',size=124), 'date': fields.date('Transaction Date'), 'cust_id': fields.many2one('devil.customer','Customer'), 'formula_line': fields.one2many('devil.items.lines','formula_id','FormulaLines'), <<<<<<< HEAD 'total_amt_disc': fields.float('Amount Discount', required=True, ), ======= >>>>>>> 08375b10183304dea2ebfe2187b2858b17177cbb 'total_amount': fields.function(_amount_all, string='TotalAmount'), 'state': fields.selection(STATE_SELECTION, 'Status', readonly=True, select=True), } _defaults = { 'state': lambda *a: 'draft', } def button_dummy(self, cr, uid, ids, context=None): return True def devil_cancel(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
class res_company(orm.Model): _inherit = "res.company" _columns = { 'date_percentage': fields.float('Date percentage'), }
class product_template(osv.osv): _name = 'product.template' _inherit = 'product.template' def _product_available(self, cr, uid, ids, name, arg, context=None): res = dict.fromkeys(ids, 0) for product in self.browse(cr, uid, ids, context=context): res[product.id] = { # "reception_count": sum([p.reception_count for p in product.product_variant_ids]), # "delivery_count": sum([p.delivery_count for p in product.product_variant_ids]), "qty_available": sum([p.qty_available for p in product.product_variant_ids]), "virtual_available": sum([p.virtual_available for p in product.product_variant_ids]), "incoming_qty": sum([p.incoming_qty for p in product.product_variant_ids]), "outgoing_qty": sum([p.outgoing_qty for p in product.product_variant_ids]), } return res def _search_product_quantity(self, cr, uid, obj, name, domain, context): prod = self.pool.get("product.product") res = [] for field, operator, value in domain: #to prevent sql injections assert field in ('qty_available', 'virtual_available', 'incoming_qty', 'outgoing_qty'), 'Invalid domain left operand' assert operator in ('<', '>', '=', '<=', '>='), 'Invalid domain operator' assert isinstance(value, (float, int)), 'Invalid domain right operand' if operator == '=': operator = '==' product_ids = prod.search(cr, uid, [], context=context) ids = [] if product_ids: #TODO: use a query instead of this browse record which is probably making the too much requests, but don't forget #the context that can be set with a location, an owner... for element in prod.browse(cr, uid, product_ids, context=context): if eval(str(element[field]) + operator + str(value)): ids.append(element.id) res.append(('product_variant_ids', 'in', ids)) return res _columns = { 'type': fields.selection([('product', 'Stockable Product'), ('consu', 'Consumable'), ('service', 'Service')], 'Product Type', required=True, help="Consumable: Will not imply stock management for this product. \nStockable product: Will imply stock management for this product."), 'property_stock_procurement': fields.property( type='many2one', relation='stock.location', string="Procurement Location", domain=[('usage','like','procurement')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated by procurements."), 'property_stock_production': fields.property( type='many2one', relation='stock.location', string="Production Location", domain=[('usage','like','production')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated by manufacturing orders."), 'property_stock_inventory': fields.property( type='many2one', relation='stock.location', string="Inventory Location", domain=[('usage','like','inventory')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated when you do an inventory."), 'sale_delay': fields.float('Customer Lead Time', help="The average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers."), 'loc_rack': fields.char('Rack', size=16), 'loc_row': fields.char('Row', size=16), 'loc_case': fields.char('Case', size=16), 'track_incoming': fields.boolean('Track Incoming Lots', help="Forces to specify a Serial Number for all moves containing this product and coming from a Supplier Location"), 'track_outgoing': fields.boolean('Track Outgoing Lots', help="Forces to specify a Serial Number for all moves containing this product and going to a Customer Location"), 'track_all': fields.boolean('Full Lots Traceability', help="Forces to specify a Serial Number on each and every operation related to this product"), # sum of product variant qty # 'reception_count': fields.function(_product_available, multi='qty_available', # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), # 'delivery_count': fields.function(_product_available, multi='qty_available', # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), 'qty_available': fields.function(_product_available, multi='qty_available', fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), 'virtual_available': fields.function(_product_available, multi='qty_available', fnct_search=_search_product_quantity, type='float', string='Quantity Available'), 'incoming_qty': fields.function(_product_available, multi='qty_available', fnct_search=_search_product_quantity, type='float', string='Incoming'), 'outgoing_qty': fields.function(_product_available, multi='qty_available', fnct_search=_search_product_quantity, type='float', string='Outgoing'), 'route_ids': fields.many2many('stock.location.route', 'stock_route_product', 'product_id', 'route_id', 'Routes', domain="[('product_selectable', '=', True)]", help="Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, manufactured, MTO/MTS,..."), } _defaults = { 'sale_delay': 7, } def action_view_routes(self, cr, uid, ids, context=None): route_obj = self.pool.get("stock.location.route") act_obj = self.pool.get('ir.actions.act_window') mod_obj = self.pool.get('ir.model.data') product_route_ids = set() for product in self.browse(cr, uid, ids, context=context): product_route_ids |= set([r.id for r in product.route_ids]) product_route_ids |= set([r.id for r in product.categ_id.total_route_ids]) route_ids = route_obj.search(cr, uid, ['|', ('id', 'in', list(product_route_ids)), ('warehouse_selectable', '=', True)], context=context) result = mod_obj.get_object_reference(cr, uid, 'stock', 'action_routes_form') id = result and result[1] or False result = act_obj.read(cr, uid, [id], context=context)[0] result['domain'] = "[('id','in',[" + ','.join(map(str, route_ids)) + "])]" return result
def selection_fn(obj, cr, uid, context=None): return list(enumerate(["Corge", "Grault", "Wheee", "Moog"])) def function_fn(model, cr, uid, ids, field_name, arg, context): return dict((id, 3) for id in ids) def function_fn_write(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context): """ just so CreatorCase.export can be used """ pass models = [ ('boolean', fields.boolean()), ('integer', fields.integer()), ('float', fields.float()), ('decimal', fields.float(digits=(16, 3))), ('string.bounded', fields.char('unknown', size=16)), ('string.required', fields.char('unknown', size=None, required=True)), ('string', fields.char('unknown', size=None)), ('date', fields.date()), ('datetime', fields.datetime()), ('text', fields.text()), ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux"), (4, '')])), # here use size=-1 to store the values as integers instead of strings ('selection.function', fields.selection(selection_fn, size=-1)), # just relate to an integer ('many2one', fields.many2one('export.integer')), ('one2many', fields.one2many('export.one2many.child', 'parent_id')), ('many2many', fields.many2many('export.many2many.other')), ('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")),
class report_project_task_user(osv.osv): _name = "report.project.task.user" _description = "Tasks by user and project" _auto = False _columns = { 'name': fields.char('Task Summary', size=128, readonly=True), 'day': fields.char('Day', size=128, readonly=True), 'year': fields.char('Year', size=64, required=False, readonly=True), 'user_id': fields.many2one('res.users', 'Assigned To', readonly=True), 'date_start': fields.date('Starting Date', readonly=True), 'no_of_days': fields.integer('# of Days', size=128, readonly=True), 'date_end': fields.date('Ending Date', readonly=True), 'date_deadline': fields.date('Deadline', readonly=True), 'project_id': fields.many2one('project.project', 'Project', readonly=True), 'hours_planned': fields.float('Planned Hours', readonly=True), 'hours_effective': fields.float('Effective Hours', readonly=True), 'hours_delay': fields.float('Avg. Plan.-Eff.', readonly=True), 'remaining_hours': fields.float('Remaining Hours', readonly=True), 'progress': fields.float('Progress', readonly=True, group_operator='avg'), 'total_hours': fields.float('Total Hours', readonly=True), 'closing_days': fields.float('Days to Close', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to close the task"), 'opening_days': fields.float('Days to Open', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to Open the task"), 'delay_endings_days': fields.float('Overpassed Deadline', digits=(16, 2), readonly=True), 'nbr': fields.integer('# of tasks', readonly=True), 'priority': fields.selection([('4', 'Very Low'), ('3', 'Low'), ('2', 'Medium'), ('1', 'Urgent'), ('0', 'Very urgent')], 'Priority', readonly=True), 'month': fields.selection([('01', 'January'), ('02', 'February'), ('03', 'March'), ('04', 'April'), ('05', 'May'), ('06', 'June'), ('07', 'July'), ('08', 'August'), ('09', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], 'Month', readonly=True), 'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'Status', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'partner_id': fields.many2one('res.partner', 'Contact', readonly=True), } _order = 'name desc, project_id' def init(self, cr): tools.sql.drop_view_if_exists(cr, 'report_project_task_user') cr.execute(""" CREATE view report_project_task_user as SELECT (select 1 ) AS nbr, t.id as id, to_char(date_start, 'YYYY') as year, to_char(date_start, 'MM') as month, to_char(date_start, 'YYYY-MM-DD') as day, date_trunc('day',t.date_start) as date_start, date_trunc('day',t.date_end) as date_end, to_date(to_char(t.date_deadline, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_deadline, -- sum(cast(to_char(date_trunc('day',t.date_end) - date_trunc('day',t.date_start),'DD') as int)) as no_of_days, abs((extract('epoch' from (t.date_end-t.date_start)))/(3600*24)) as no_of_days, t.user_id, progress as progress, t.project_id, t.state, t.effective_hours as hours_effective, t.priority, t.name as name, t.company_id, t.partner_id, t.stage_id, remaining_hours as remaining_hours, total_hours as total_hours, t.delay_hours as hours_delay, planned_hours as hours_planned, (extract('epoch' from (t.date_end-t.create_date)))/(3600*24) as closing_days, (extract('epoch' from (t.date_start-t.create_date)))/(3600*24) as opening_days, abs((extract('epoch' from (t.date_deadline-t.date_end)))/(3600*24)) as delay_endings_days FROM project_task t WHERE t.active = 'true' GROUP BY t.id, remaining_hours, t.effective_hours, progress, total_hours, planned_hours, hours_delay, year, month, day, create_date, date_start, date_end, date_deadline, t.user_id, t.project_id, t.state, t.priority, name, t.company_id, t.partner_id, t.stage_id """)
# You should have received a copy of the GNU Affero General Public License # # along with this program. If not, see <http://www.gnu.org/licenses/>. # ############################################################################### import time from openerp.osv import orm, fields from openerp.addons import decimal_precision as dp from .res_company import COMPANY_FISCAL_TYPE, COMPANY_FISCAL_TYPE_DEFAULT FISCAL_RULE_COLUMNS = { "partner_fiscal_type_id": fields.many2one("l10n_br_account.partner.fiscal.type", "Tipo Fiscal do Parceiro"), "fiscal_category_id": fields.many2one("l10n_br_account.fiscal.category", "Categoria"), "fiscal_type": fields.selection(COMPANY_FISCAL_TYPE, u"Regime Tributário", required=True), "revenue_start": fields.float( "Faturamento Inicial", digits_compute=dp.get_precision("Account"), help="Faixa inicial de faturamento bruto" ), "revenue_end": fields.float( "Faturamento Final", digits_compute=dp.get_precision("Account"), help="Faixa inicial de faturamento bruto" ), } OTHERS_FISCAL_RULE_COLUMNS_TEMPLATE = { "parent_id": fields.many2one("account.fiscal.position.rule.template", "Regra Pai"), "child_ids": fields.one2many("account.fiscal.position.rule.template", "parent_id", "Regras Filhas"), } OTHERS_FISCAL_RULE_COLUMNS = { "parent_id": fields.many2one("account.fiscal.position.rule", "Regra Pai"), "child_ids": fields.one2many("account.fiscal.position.rule", "parent_id", "Regras Filhas"), }
WHERE rel.invoice_id = ANY(%s)""", (list(ids),)) return [i[0] for i in cr.fetchall()] _name = 'sale.order.line' _description = 'Sales Order Line' _columns = { 'order_id': fields.many2one('sale.order', 'Order Reference', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}), 'name': fields.text('Description', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of sales order lines."), 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True), 'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True), 'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean', store={ 'account.invoice': (_order_lines_from_invoice, ['state'], 10), 'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)}), 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}), 'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."), 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), 'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}), 'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."), 'product_uom_qty': fields.float('Quantity', digits_compute= dp.get_precision('Product UoS'), required=True, readonly=True, states={'draft': [('readonly', False)]}), 'product_uom': fields.many2one('product.uom', 'Unit of Measure ', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'product_uos_qty': fields.float('Quantity (UoS)' ,digits_compute= dp.get_precision('Product UoS'), readonly=True, states={'draft': [('readonly', False)]}), 'product_uos': fields.many2one('product.uom', 'Product UoS'), 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount'), readonly=True, states={'draft': [('readonly', False)]}), 'th_weight': fields.float('Weight', readonly=True, states={'draft': [('readonly', False)]}), 'state': fields.selection([('cancel', 'Cancelled'),('draft', 'Draft'),('confirmed', 'Confirmed'),('exception', 'Exception'),('done', 'Done')], 'Status', required=True, readonly=True, help='* The \'Draft\' status is set when the related sales order in draft status. \ \n* The \'Confirmed\' status is set when the related sales order is confirmed. \ \n* The \'Exception\' status is set when the related sales order is set as exception. \
class account_bank_statement(osv.osv): def create(self, cr, uid, vals, context=None): if vals.get('name', '/') == '/': journal_id = vals.get('journal_id', self._default_journal_id(cr, uid, context=context)) vals['name'] = self._compute_default_statement_name(cr, uid, journal_id, context=context) if 'line_ids' in vals: for idx, line in enumerate(vals['line_ids']): line[2]['sequence'] = idx + 1 return super(account_bank_statement, self).create(cr, uid, vals, context=context) def write(self, cr, uid, ids, vals, context=None): res = super(account_bank_statement, self).write(cr, uid, ids, vals, context=context) account_bank_statement_line_obj = self.pool.get('account.bank.statement.line') for statement in self.browse(cr, uid, ids, context): for idx, line in enumerate(statement.line_ids): account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': idx + 1}, context=context) return res def _default_journal_id(self, cr, uid, context=None): if context is None: context = {} journal_pool = self.pool.get('account.journal') journal_type = context.get('journal_type', False) company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=context) if journal_type: ids = journal_pool.search(cr, uid, [('type', '=', journal_type),('company_id','=',company_id)]) if ids: return ids[0] return False def _end_balance(self, cursor, user, ids, name, attr, context=None): res = {} for statement in self.browse(cursor, user, ids, context=context): res[statement.id] = statement.balance_start for line in statement.line_ids: res[statement.id] += line.amount return res def _get_period(self, cr, uid, context=None): periods = self.pool.get('account.period').find(cr, uid, context=context) if periods: return periods[0] return False def _compute_default_statement_name(self, cr, uid, journal_id, context=None): if context is None: context = {} obj_seq = self.pool.get('ir.sequence') period = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, context=context), context=context) context['fiscalyear_id'] = period.fiscalyear_id.id journal = self.pool.get('account.journal').browse(cr, uid, journal_id, None) return obj_seq.next_by_id(cr, uid, journal.sequence_id.id, context=context) def _currency(self, cursor, user, ids, name, args, context=None): res = {} res_currency_obj = self.pool.get('res.currency') res_users_obj = self.pool.get('res.users') default_currency = res_users_obj.browse(cursor, user, user, context=context).company_id.currency_id for statement in self.browse(cursor, user, ids, context=context): currency = statement.journal_id.currency if not currency: currency = default_currency res[statement.id] = currency.id currency_names = {} for currency_id, currency_name in res_currency_obj.name_get(cursor, user, [x for x in res.values()], context=context): currency_names[currency_id] = currency_name for statement_id in res.keys(): currency_id = res[statement_id] res[statement_id] = (currency_id, currency_names[currency_id]) return res def _get_statement(self, cr, uid, ids, context=None): result = {} for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context): result[line.statement_id.id] = True return result.keys() def _all_lines_reconciled(self, cr, uid, ids, name, args, context=None): res = {} for statement in self.browse(cr, uid, ids, context=context): res[statement.id] = all([line.journal_entry_id.id for line in statement.line_ids]) return res _order = "date desc, id desc" _name = "account.bank.statement" _description = "Bank Statement" _inherit = ['mail.thread'] _columns = { 'name': fields.char('Reference', size=64, states={'draft': [('readonly', False)]}, readonly=True, help='if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself'), # readonly for account_cash_statement 'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'period_id': fields.many2one('account.period', 'Period', required=True, states={'confirm':[('readonly', True)]}), 'balance_start': fields.float('Starting Balance', digits_compute=dp.get_precision('Account'), states={'confirm':[('readonly',True)]}), 'balance_end_real': fields.float('Ending Balance', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}, help="Computed using the cash control lines"), 'balance_end': fields.function(_end_balance, store = { 'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids','balance_start'], 10), 'account.bank.statement.line': (_get_statement, ['amount'], 10), }, string="Computed Balance", help='Balance as calculated based on Opening Balance and transaction lines'), 'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), 'line_ids': fields.one2many('account.bank.statement.line', 'statement_id', 'Statement lines', states={'confirm':[('readonly', True)]}), 'move_line_ids': fields.one2many('account.move.line', 'statement_id', 'Entry lines', states={'confirm':[('readonly',True)]}), 'state': fields.selection([('draft', 'New'), ('open','Open'), # used by cash statements ('confirm', 'Closed')], 'Status', required=True, readonly="1", help='When new statement is created the status will be \'Draft\'.\n' 'And after getting confirmation from the bank it will be in \'Confirmed\' status.'), 'currency': fields.function(_currency, string='Currency', type='many2one', relation='res.currency'), 'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'), 'cash_control': fields.related('journal_id', 'cash_control' , type='boolean', relation='account.journal',string='Cash control'), 'all_lines_reconciled': fields.function(_all_lines_reconciled, string='All lines reconciled', type='boolean'), } _defaults = { 'name': '/', 'date': fields.date.context_today, 'state': 'draft', 'journal_id': _default_journal_id, 'period_id': _get_period, 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement',context=c), } def _check_company_id(self, cr, uid, ids, context=None): for statement in self.browse(cr, uid, ids, context=context): if statement.company_id.id != statement.period_id.company_id.id: return False return True _constraints = [ (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']), ] def onchange_date(self, cr, uid, ids, date, company_id, context=None): """ Find the correct period to use for the given date and company_id, return it and set it in the context """ res = {} period_pool = self.pool.get('account.period') if context is None: context = {} ctx = context.copy() ctx.update({'company_id': company_id}) pids = period_pool.find(cr, uid, dt=date, context=ctx) if pids: res.update({'period_id': pids[0]}) context.update({'period_id': pids[0]}) return { 'value':res, 'context':context, } def button_dummy(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {}, context=context) def _prepare_move(self, cr, uid, st_line, st_line_number, context=None): """Prepare the dict of values to create the move from a statement line. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :param char st_line_number: will be used as the name of the generated account move :return: dict of value to create() the account.move """ return { 'journal_id': st_line.statement_id.journal_id.id, 'period_id': st_line.statement_id.period_id.id, 'date': st_line.date, 'name': st_line_number, 'ref': st_line.ref, } def _get_counter_part_account(sefl, cr, uid, st_line, context=None): """Retrieve the account to use in the counterpart move. :param browse_record st_line: account.bank.statement.line record to create the move from. :return: int/long of the account.account to use as counterpart """ if st_line.amount >= 0: return st_line.statement_id.journal_id.default_credit_account_id.id return st_line.statement_id.journal_id.default_debit_account_id.id def _get_counter_part_partner(sefl, cr, uid, st_line, context=None): """Retrieve the partner to use in the counterpart move. :param browse_record st_line: account.bank.statement.line record to create the move from. :return: int/long of the res.partner to use as counterpart """ return st_line.partner_id and st_line.partner_id.id or False def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None): """Compute the args to build the dict of values to create the counter part move line from a statement line by calling the _prepare_move_line_vals. :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line :param float amount: amount of the move line :param int/long company_currency_id: ID of currency of the concerned company :return: dict of value to create() the bank account.move.line """ account_id = self._get_counter_part_account(cr, uid, st_line, context=context) partner_id = self._get_counter_part_partner(cr, uid, st_line, context=context) debit = ((amount > 0) and amount) or 0.0 credit = ((amount < 0) and -amount) or 0.0 cur_id = False amt_cur = False if st_line.statement_id.currency.id != company_currency_id: amt_cur = st_line.amount cur_id = st_line.currency_id or st_line.statement_id.currency.id if st_line.currency_id and st_line.amount_currency: amt_cur = st_line.amount_currency cur_id = st_line.currency_id.id return self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit, amount_currency=amt_cur, currency_id=cur_id, account_id=account_id, partner_id=partner_id, context=context) def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id=False, amount_currency=False, account_id=False, partner_id=False, context=None): """Prepare the dict of values to create the move line from a statement line. :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line :param float debit: debit amount of the move line :param float credit: credit amount of the move line :param int/long currency_id: ID of currency of the move line to create :param float amount_currency: amount of the debit/credit expressed in the currency_id :param int/long account_id: ID of the account to use in the move line if different from the statement line account ID :param int/long partner_id: ID of the partner to put on the move line :return: dict of value to create() the account.move.line """ acc_id = account_id or st_line.account_id.id cur_id = currency_id or st_line.statement_id.currency.id par_id = partner_id or (((st_line.partner_id) and st_line.partner_id.id) or False) return { 'name': st_line.name, 'date': st_line.date, 'ref': st_line.ref, 'move_id': move_id, 'partner_id': par_id, 'account_id': acc_id, 'credit': credit, 'debit': debit, 'statement_id': st_line.statement_id.id, 'journal_id': st_line.statement_id.journal_id.id, 'period_id': st_line.statement_id.period_id.id, 'currency_id': amount_currency and cur_id, 'amount_currency': amount_currency, } def balance_check(self, cr, uid, st_id, journal_type='bank', context=None): st = self.browse(cr, uid, st_id, context=context) if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)): raise osv.except_osv(_('Error!'), _('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)') % (st.balance_end_real, st.balance_end)) return True def statement_close(self, cr, uid, ids, journal_type='bank', context=None): return self.write(cr, uid, ids, {'state':'confirm'}, context=context) def check_status_condition(self, cr, uid, state, journal_type='bank'): return state in ('draft','open') def button_confirm_bank(self, cr, uid, ids, context=None): if context is None: context = {} for st in self.browse(cr, uid, ids, context=context): j_type = st.journal_id.type if not self.check_status_condition(cr, uid, st.state, journal_type=j_type): continue self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) if (not st.journal_id.default_credit_account_id) \ or (not st.journal_id.default_debit_account_id): raise osv.except_osv(_('Configuration Error!'), _('Please verify that an account is defined in the journal.')) for line in st.move_line_ids: if line.state <> 'valid': raise osv.except_osv(_('Error!'), _('The account entries lines are not in valid state.')) move_ids = [] for st_line in st.line_ids: if not st_line.amount: continue if not st_line.journal_entry_id.id: raise osv.except_osv(_('Error!'), _('All the account entries lines must be processed in order to close the statement.')) move_ids.append(st_line.journal_entry_id.id) self.pool.get('account.move').post(cr, uid, move_ids, context=context) self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st.name,), context=context) self.link_bank_to_partner(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'confirm'}, context=context) def button_cancel(self, cr, uid, ids, context=None): account_move_obj = self.pool.get('account.move') reconcile_pool = self.pool.get('account.move.reconcile') move_line_pool = self.pool.get('account.move.line') move_ids = [] for st in self.browse(cr, uid, ids, context=context): for line in st.line_ids: if line.journal_entry_id: move_ids.append(line.journal_entry_id.id) for aml in line.journal_entry_id.line_id: if aml.reconcile_id: move_lines = [l.id for l in aml.reconcile_id.line_id] move_lines.remove(aml.id) reconcile_pool.unlink(cr, uid, [aml.reconcile_id.id], context=context) if len(move_lines) >= 2: move_line_pool.reconcile_partial(cr, uid, move_lines, 'auto', context=context) if move_ids: account_move_obj.button_cancel(cr, uid, move_ids, context=context) account_move_obj.unlink(cr, uid, move_ids, context) return self.write(cr, uid, ids, {'state': 'draft'}, context=context) def _compute_balance_end_real(self, cr, uid, journal_id, context=None): res = False if journal_id: journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) if journal.with_last_closing_balance: cr.execute('SELECT balance_end_real \ FROM account_bank_statement \ WHERE journal_id = %s AND NOT state = %s \ ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft')) res = cr.fetchone() return res and res[0] or 0.0 def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None): if not journal_id: return {} balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context) journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context) currency = journal.currency or journal.company_id.currency_id res = {'balance_start': balance_start, 'company_id': journal.company_id.id, 'currency': currency.id} if journal.type == 'cash': res['cash_control'] = journal.cash_control return {'value': res} def unlink(self, cr, uid, ids, context=None): stat = self.read(cr, uid, ids, ['state'], context=context) unlink_ids = [] for t in stat: if t['state'] in ('draft'): unlink_ids.append(t['id']) else: raise osv.except_osv(_('Invalid Action!'), _('In order to delete a bank statement, you must first cancel it to delete related journal items.')) osv.osv.unlink(self, cr, uid, unlink_ids, context=context) return True def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} if context is None: context = {} default = default.copy() default['move_line_ids'] = [] return super(account_bank_statement, self).copy(cr, uid, id, default, context=context) def button_journal_entries(self, cr, uid, ids, context=None): ctx = (context or {}).copy() ctx['journal_id'] = self.browse(cr, uid, ids[0], context=context).journal_id.id return { 'name': _('Journal Items'), 'view_type':'form', 'view_mode':'tree', 'res_model':'account.move.line', 'view_id':False, 'type':'ir.actions.act_window', 'domain':[('statement_id','in',ids)], 'context':ctx, } def number_of_lines_reconciled(self, cr, uid, id, context=None): bsl_obj = self.pool.get('account.bank.statement.line') return bsl_obj.search_count(cr, uid, [('statement_id', '=', id), ('journal_entry_id', '!=', False)], context=context) def get_format_currency_js_function(self, cr, uid, id, context=None): """ Returns a string that can be used to instanciate a javascript function. That function formats a number according to the statement line's currency or the statement currency""" company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id st = id and self.browse(cr, uid, id, context=context) if not st: return statement_currency = st.journal_id.currency or company_currency digits = 2 # TODO : from currency_obj function = "" done_currencies = [] for st_line in st.line_ids: st_line_currency = st_line.currency_id or statement_currency if st_line_currency.id not in done_currencies: if st_line_currency.position == 'after': return_str = "return amount.toFixed(" + str(digits) + ") + ' " + st_line_currency.symbol + "';" else: return_str = "return '" + st_line_currency.symbol + " ' + amount.toFixed(" + str(digits) + ");" function += "if (currency_id === " + str(st_line_currency.id) + "){ " + return_str + " }" done_currencies.append(st_line_currency.id) return function def link_bank_to_partner(self, cr, uid, ids, context=None): for statement in self.browse(cr, uid, ids, context=context): for st_line in statement.line_ids: if st_line.bank_account_id and st_line.partner_id and st_line.bank_account_id.partner_id.id != st_line.partner_id.id: self.pool.get('res.partner.bank').write(cr, uid, [st_line.bank_account_id.id], {'partner_id': st_line.partner_id.id}, context=context)
class account_bank_statement_line(osv.osv): def get_data_for_reconciliations(self, cr, uid, ids, context=None): """ Used to instanciate a batch of reconciliations in a single request """ # Build a list of reconciliations data ret = [] mv_line_ids_selected = [] for st_line_id in ids: reconciliation_data = { 'st_line': self.get_statement_line_for_reconciliation(cr, uid, st_line_id, context), 'reconciliation_proposition': self.get_reconciliation_proposition(cr, uid, st_line_id, mv_line_ids_selected, context) } for mv_line in reconciliation_data['reconciliation_proposition']: mv_line_ids_selected.append(mv_line['id']) ret.append(reconciliation_data) # Check if, now that 'candidate' move lines were selected, there are moves left for statement lines #for reconciliation_data in ret: # if not reconciliation_data['st_line']['has_no_partner']: # st_line = self.browse(cr, uid, reconciliation_data['st_line']['id'], context=context) # if not self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=mv_line_ids_selected, count=True, context=context): # reconciliation_data['st_line']['no_match'] = True return ret def get_statement_line_for_reconciliation(self, cr, uid, id, context=None): """ Returns the data required by the bank statement reconciliation use case """ line = self.browse(cr, uid, id, context=context) statement_currency = line.journal_id.currency or line.journal_id.company_id.currency_id amount = line.amount rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_widget', context=context) amount_str = line.amount > 0 and line.amount or -line.amount amount_str = rml_parser.formatLang(amount_str, currency_obj=statement_currency) amount_currency_str = "" if line.amount_currency and line.currency_id: amount_currency_str = amount_str amount_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id) amount = line.amount_currency data = { 'id': line.id, 'ref': line.ref, 'note': line.note or "", 'name': line.name, 'date': line.date, 'amount': amount, 'amount_str': amount_str, 'currency_id': line.currency_id.id or statement_currency.id, 'no_match': self.get_move_lines_counterparts(cr, uid, line, count=True, context=context) == 0, 'partner_id': line.partner_id.id, 'statement_id': line.statement_id.id, 'account_code': line.journal_id.default_debit_account_id.code, 'account_name': line.journal_id.default_debit_account_id.name, 'partner_name': line.partner_id.name, 'amount_currency_str': amount_currency_str, 'has_no_partner': not line.partner_id.id, } if line.partner_id.id: data['open_balance_account_id'] = line.partner_id.property_account_payable.id if amount > 0: data['open_balance_account_id'] = line.partner_id.property_account_receivable.id return data def search_structured_com(self, cr, uid, st_line, context=None): if not st_line.ref: return domain = [('ref', '=', st_line.ref)] if st_line.partner_id: domain += [('partner_id', '=', st_line.partner_id.id)] ids = self.pool.get('account.move.line').search(cr, uid, domain, limit=1, context=context) return ids and ids[0] or False def get_reconciliation_proposition(self, cr, uid, id, excluded_ids=[], context=None): """ Returns move lines that constitute the best guess to reconcile a statement line. """ st_line = self.browse(cr, uid, id, context=context) company_currency = st_line.journal_id.company_id.currency_id.id statement_currency = st_line.journal_id.currency.id or company_currency # either use the unsigned debit/credit fields or the signed amount_currency field sign = 1 if statement_currency == company_currency: amount_field = 'credit' if st_line.amount > 0: amount_field = 'debit' else: amount_field = 'amount_currency' if st_line.amount < 0: sign = -1 # look for structured communication exact_match_id = self.search_structured_com(cr, uid, st_line, context=context) if exact_match_id: return self.make_counter_part_lines(cr, uid, st_line, [exact_match_id], count=False, context=context) #we don't propose anything if there is no partner detected if not st_line.partner_id.id: return [] # look for exact match exact_match_id = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=1, additional_domain=[(amount_field, '=', (sign * st_line.amount))]) if exact_match_id: return exact_match_id # select oldest move lines if sign == -1: mv_lines = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field, '<', 0)]) else: mv_lines = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field, '>', 0)]) ret = [] total = 0 # get_move_lines_counterparts inverts debit and credit amount_field = 'debit' if amount_field == 'credit' else 'credit' for line in mv_lines: if total + line[amount_field] <= abs(st_line.amount): ret.append(line) total += line[amount_field] if total >= abs(st_line.amount): break return ret def get_move_lines_counterparts_id(self, cr, uid, st_line_id, excluded_ids=[], filter_str="", offset=0, limit=None, count=False, additional_domain=[], context=None): st_line = self.browse(cr, uid, st_line_id, context=context) return self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids, filter_str, offset, limit, count, additional_domain, context=context) def get_move_lines_counterparts(self, cr, uid, st_line, excluded_ids=[], filter_str="", offset=0, limit=None, count=False, additional_domain=[], context=None): """ Find the move lines that could be used to reconcile a statement line and returns the counterpart that could be created to reconcile them If count is true, only returns the count. :param st_line: the browse record of the statement line :param integers list excluded_ids: ids of move lines that should not be fetched :param string filter_str: string to filter lines :param integer offset: offset of the request :param integer limit: number of lines to fetch :param boolean count: just return the number of records :param tuples list domain: additional domain restrictions """ mv_line_pool = self.pool.get('account.move.line') domain = additional_domain + [ ('reconcile_id', '=', False), ('state', '=', 'valid'), ] if st_line.partner_id.id: domain += [('partner_id', '=', st_line.partner_id.id), '|', ('account_id.type', '=', 'receivable'), ('account_id.type', '=', 'payable')] else: domain += [('account_id.reconcile', '=', True)] #domain += [('account_id.reconcile', '=', True), ('account_id.type', '=', 'other')] if excluded_ids: domain.append(('id', 'not in', excluded_ids)) if filter_str: if not st_line.partner_id: domain += [ '|', ('partner_id.name', 'ilike', filter_str)] domain += ['|', ('move_id.name', 'ilike', filter_str), ('move_id.ref', 'ilike', filter_str)] line_ids = mv_line_pool.search(cr, uid, domain, offset=offset, limit=limit, order="date_maturity asc, id asc", context=context) return self.make_counter_part_lines(cr, uid, st_line, line_ids, count=count, context=context) def make_counter_part_lines(self, cr, uid, st_line, line_ids, count=False, context=None): if context is None: context = {} mv_line_pool = self.pool.get('account.move.line') currency_obj = self.pool.get('res.currency') company_currency = st_line.journal_id.company_id.currency_id statement_currency = st_line.journal_id.currency or company_currency rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_counterpart_widget', context=context) #partially reconciled lines can be displayed only once reconcile_partial_ids = [] if count: nb_lines = 0 for line in mv_line_pool.browse(cr, uid, line_ids, context=context): if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids: continue nb_lines += 1 if line.reconcile_partial_id: reconcile_partial_ids.append(line.reconcile_partial_id.id) return nb_lines else: ret = [] for line in mv_line_pool.browse(cr, uid, line_ids, context=context): if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids: continue amount_currency_str = "" if line.currency_id and line.amount_currency: amount_currency_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id) ret_line = { 'id': line.id, 'name': line.move_id.name, 'ref': line.move_id.ref, 'account_code': line.account_id.code, 'account_name': line.account_id.name, 'account_type': line.account_id.type, 'date_maturity': line.date_maturity, 'date': line.date, 'period_name': line.period_id.name, 'journal_name': line.journal_id.name, 'amount_currency_str': amount_currency_str, 'partner_id': line.partner_id.id, 'partner_name': line.partner_id.name, 'has_no_partner': not bool(st_line.partner_id.id), } st_line_currency = st_line.currency_id or statement_currency if st_line.currency_id and line.currency_id and line.currency_id.id == st_line.currency_id.id: if line.amount_residual_currency < 0: ret_line['debit'] = 0 ret_line['credit'] = -line.amount_residual_currency else: ret_line['debit'] = line.amount_residual_currency if line.credit != 0 else 0 ret_line['credit'] = line.amount_residual_currency if line.debit != 0 else 0 ret_line['amount_currency_str'] = rml_parser.formatLang(line.amount_residual, currency_obj=company_currency) else: if line.amount_residual < 0: ret_line['debit'] = 0 ret_line['credit'] = -line.amount_residual else: ret_line['debit'] = line.amount_residual if line.credit != 0 else 0 ret_line['credit'] = line.amount_residual if line.debit != 0 else 0 ctx = context.copy() ctx.update({'date': st_line.date}) ret_line['debit'] = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, ret_line['debit'], context=ctx) ret_line['credit'] = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, ret_line['credit'], context=ctx) ret_line['debit_str'] = rml_parser.formatLang(ret_line['debit'], currency_obj=st_line_currency) ret_line['credit_str'] = rml_parser.formatLang(ret_line['credit'], currency_obj=st_line_currency) ret.append(ret_line) if line.reconcile_partial_id: reconcile_partial_ids.append(line.reconcile_partial_id.id) return ret def get_currency_rate_line(self, cr, uid, st_line, currency_diff, move_id, context=None): if currency_diff < 0: account_id = st_line.company_id.expense_currency_exchange_account_id.id if not account_id: raise osv.except_osv(_('Insufficient Configuration!'), _("You should configure the 'Loss Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates.")) else: account_id = st_line.company_id.income_currency_exchange_account_id.id if not account_id: raise osv.except_osv(_('Insufficient Configuration!'), _("You should configure the 'Gain Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates.")) return { 'move_id': move_id, 'name': _('change') + ': ' + (st_line.name or '/'), 'period_id': st_line.statement_id.period_id.id, 'journal_id': st_line.journal_id.id, 'partner_id': st_line.partner_id.id, 'company_id': st_line.company_id.id, 'statement_id': st_line.statement_id.id, 'debit': currency_diff < 0 and -currency_diff or 0, 'credit': currency_diff > 0 and currency_diff or 0, 'date': st_line.date, 'account_id': account_id } def process_reconciliation(self, cr, uid, id, mv_line_dicts, context=None): """ Creates a move line for each item of mv_line_dicts and for the statement line. Reconcile a new move line with its counterpart_move_line_id if specified. Finally, mark the statement line as reconciled by putting the newly created move id in the column journal_entry_id. :param int id: id of the bank statement line :param list of dicts mv_line_dicts: move lines to create. If counterpart_move_line_id is specified, reconcile with it """ if context is None: context = {} st_line = self.browse(cr, uid, id, context=context) company_currency = st_line.journal_id.company_id.currency_id statement_currency = st_line.journal_id.currency or company_currency bs_obj = self.pool.get('account.bank.statement') am_obj = self.pool.get('account.move') aml_obj = self.pool.get('account.move.line') currency_obj = self.pool.get('res.currency') # Checks if st_line.journal_entry_id.id: raise osv.except_osv(_('Error!'), _('The bank statement line was already reconciled.')) for mv_line_dict in mv_line_dicts: for field in ['debit', 'credit', 'amount_currency']: if field not in mv_line_dict: mv_line_dict[field] = 0.0 if mv_line_dict.get('counterpart_move_line_id'): mv_line = aml_obj.browse(cr, uid, mv_line_dict.get('counterpart_move_line_id'), context=context) if mv_line.reconcile_id: raise osv.except_osv(_('Error!'), _('A selected move line was already reconciled.')) # Create the move move_name = st_line.statement_id.name + "/" + str(st_line.sequence) move_vals = bs_obj._prepare_move(cr, uid, st_line, move_name, context=context) move_id = am_obj.create(cr, uid, move_vals, context=context) # Create the move line for the statement line amount = currency_obj.compute(cr, uid, st_line.statement_id.currency.id, company_currency.id, st_line.amount, context=context) bank_st_move_vals = bs_obj._prepare_bank_move_line(cr, uid, st_line, move_id, amount, company_currency.id, context=context) aml_obj.create(cr, uid, bank_st_move_vals, context=context) # Complete the dicts st_line_currency = st_line.currency_id or statement_currency st_line_currency_rate = st_line.currency_id and statement_currency.id == company_currency.id and (st_line.amount_currency / st_line.amount) or False to_create = [] for mv_line_dict in mv_line_dicts: mv_line_dict['ref'] = move_name mv_line_dict['move_id'] = move_id mv_line_dict['period_id'] = st_line.statement_id.period_id.id mv_line_dict['journal_id'] = st_line.journal_id.id mv_line_dict['company_id'] = st_line.company_id.id mv_line_dict['statement_id'] = st_line.statement_id.id if mv_line_dict.get('counterpart_move_line_id'): mv_line = aml_obj.browse(cr, uid, mv_line_dict['counterpart_move_line_id'], context=context) mv_line_dict['account_id'] = mv_line.account_id.id if st_line_currency.id != company_currency.id: mv_line_dict['amount_currency'] = mv_line_dict['debit'] - mv_line_dict['credit'] mv_line_dict['currency_id'] = st_line_currency.id if st_line.currency_id and statement_currency.id == company_currency.id and st_line_currency_rate: debit_at_current_rate = self.pool.get('res.currency').round(cr, uid, company_currency, mv_line_dict['debit'] / st_line_currency_rate) credit_at_current_rate = self.pool.get('res.currency').round(cr, uid, company_currency, mv_line_dict['credit'] / st_line_currency_rate) else: debit_at_current_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['debit'], context=context) credit_at_current_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['credit'], context=context) if mv_line_dict.get('counterpart_move_line_id'): #post an account line that use the same currency rate than the counterpart (to balance the account) and post the difference in another line ctx = context.copy() ctx['date'] = mv_line.date debit_at_old_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['debit'], context=ctx) credit_at_old_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['credit'], context=ctx) mv_line_dict['credit'] = credit_at_old_rate mv_line_dict['debit'] = debit_at_old_rate if debit_at_old_rate - debit_at_current_rate: currency_diff = debit_at_current_rate - debit_at_old_rate to_create.append(self.get_currency_rate_line(cr, uid, st_line, currency_diff, move_id, context=context)) if credit_at_old_rate - credit_at_current_rate: currency_diff = credit_at_current_rate - credit_at_old_rate to_create.append(self.get_currency_rate_line(cr, uid, st_line, currency_diff, move_id, context=context)) else: mv_line_dict['debit'] = debit_at_current_rate mv_line_dict['credit'] = credit_at_current_rate to_create.append(mv_line_dict) # Create move lines move_line_pairs_to_reconcile = [] for mv_line_dict in to_create: counterpart_move_line_id = None # NB : this attribute is irrelevant for aml_obj.create() and needs to be removed from the dict if mv_line_dict.get('counterpart_move_line_id'): counterpart_move_line_id = mv_line_dict['counterpart_move_line_id'] del mv_line_dict['counterpart_move_line_id'] new_aml_id = aml_obj.create(cr, uid, mv_line_dict, context=context) if counterpart_move_line_id != None: move_line_pairs_to_reconcile.append([new_aml_id, counterpart_move_line_id]) # Reconcile for pair in move_line_pairs_to_reconcile: # TODO : too slow aml_obj.reconcile_partial(cr, uid, pair, context=context) # Mark the statement line as reconciled self.write(cr, uid, id, {'journal_entry_id': move_id}, context=context) # FIXME : if it wasn't for the multicompany security settings in account_security.xml, the method would just # return [('journal_entry_id', '=', False)] # Unfortunately, that spawns a "no access rights" error ; it shouldn't. def _needaction_domain_get(self, cr, uid, context=None): user = self.pool.get("res.users").browse(cr, uid, uid) return ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id]),('journal_entry_id', '=', False)] _order = "statement_id desc, sequence" _name = "account.bank.statement.line" _description = "Bank Statement Line" _inherit = ['ir.needaction_mixin'] _columns = { 'name': fields.char('Description', required=True), 'date': fields.date('Date', required=True), 'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')), 'partner_id': fields.many2one('res.partner', 'Partner'), 'bank_account_id': fields.many2one('res.partner.bank','Bank Account'), 'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True, required=True, ondelete='cascade'), 'journal_id': fields.related('statement_id', 'journal_id', type='many2one', relation='account.journal', string='Journal', store=True, readonly=True), 'ref': fields.char('Structured Communication'), 'note': fields.text('Notes'), 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of bank statement lines."), 'company_id': fields.related('statement_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), 'journal_entry_id': fields.many2one('account.move', 'Journal Entry'), 'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')), 'currency_id': fields.many2one('res.currency', 'Currency', help="The optional other currency if it is a multi-currency entry."), } _defaults = { 'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.bank.statement.line'), 'date': lambda self,cr,uid,context={}: context.get('date', fields.date.context_today(self,cr,uid,context=context)), }
class crm_lead_report(osv.Model): """ CRM Lead Analysis """ _name = "crm.lead.report" _auto = False _description = "CRM Lead Analysis" _rec_name = 'date_deadline' _inherit = ["crm.tracking.mixin"] _columns = { 'date_deadline': fields.date('Exp. Closing', readonly=True, help="Expected Closing"), 'create_date': fields.datetime('Creation Date', readonly=True), 'opening_date': fields.datetime('Assignation Date', readonly=True), 'date_closed': fields.datetime('Close Date', readonly=True), 'date_last_stage_update': fields.datetime('Last Stage Update', readonly=True), 'nbr_cases': fields.integer("# of Cases", readonly=True), # durations 'delay_open': fields.float('Delay to Assign', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to open the case"), 'delay_close': fields.float('Delay to Close', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to close the case"), 'delay_expected': fields.float('Overpassed Deadline', digits=(16, 2), readonly=True, group_operator="avg"), 'user_id': fields.many2one('res.users', 'User', readonly=True), 'team_id': fields.many2one('crm.team', 'Sales Team', oldname='section_id', readonly=True), 'country_id': fields.many2one('res.country', 'Country', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'probability': fields.float('Probability', digits=(16, 2), readonly=True, group_operator="avg"), 'planned_revenue': fields.float( 'Total Revenue', digits=(16, 2), readonly=True), # TDE FIXME master: rename into total_revenue 'probable_revenue': fields.float( 'Expected Revenue', digits=(16, 2), readonly=True), # TDE FIXME master: rename into expected_revenue 'stage_id': fields.many2one('crm.stage', 'Stage', readonly=True, domain="[('team_ids', '=', team_id)]"), 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'), 'type': fields.selection( [ ('lead', 'Lead'), ('opportunity', 'Opportunity'), ], 'Type', help="Type is used to separate Leads and Opportunities"), } def init(self, cr): """ CRM Lead Report @param cr: the current row, from the database cursor """ tools.drop_view_if_exists(cr, 'crm_lead_report') cr.execute(""" CREATE OR REPLACE VIEW crm_lead_report AS ( SELECT id, c.date_deadline, count(id) as nbr_cases, c.date_open as opening_date, c.date_closed as date_closed, c.date_last_stage_update as date_last_stage_update, c.user_id, c.probability, c.stage_id, c.type, c.company_id, c.priority, c.team_id, c.campaign_id, c.source_id, c.medium_id, c.partner_id, c.country_id, c.planned_revenue as planned_revenue, c.planned_revenue*(c.probability/100) as probable_revenue, c.create_date as create_date, extract('epoch' from (c.date_closed-c.create_date))/(3600*24) as delay_close, abs(extract('epoch' from (c.date_deadline - c.date_closed))/(3600*24)) as delay_expected, extract('epoch' from (c.date_open-c.create_date))/(3600*24) as delay_open FROM crm_lead c WHERE c.active = 'true' GROUP BY c.id )""")
class stock_history(osv.osv): _name = 'stock.history' _auto = False _order = 'date asc' def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True): res = super(stock_history, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy) if context is None: context = {} date = context.get('history_date', datetime.now()) if 'inventory_value' in fields: group_lines = {} for line in res: domain = line.get('__domain', []) group_lines.setdefault( str(domain), self.search(cr, uid, domain, context=context)) line_ids = set() for ids in group_lines.values(): for product_id in ids: line_ids.add(product_id) line_ids = list(line_ids) lines_rec = {} if line_ids: cr.execute( 'SELECT id, product_id, price_unit_on_quant, company_id, quantity FROM stock_history WHERE id in %s', (tuple(line_ids), )) lines_rec = cr.dictfetchall() lines_dict = dict((line['id'], line) for line in lines_rec) product_ids = list( set(line_rec['product_id'] for line_rec in lines_rec)) products_rec = self.pool['product.product'].read( cr, uid, product_ids, ['cost_method', 'id'], context=context) products_dict = dict( (product['id'], product) for product in products_rec) cost_method_product_ids = list( set(product['id'] for product in products_rec if product['cost_method'] != 'real')) histories = [] if cost_method_product_ids: cr.execute( 'SELECT DISTINCT ON (product_id, company_id) product_id, company_id, cost FROM product_price_history WHERE product_id in %s AND datetime <= %s ORDER BY product_id, company_id, datetime DESC', (tuple(cost_method_product_ids), date)) histories = cr.dictfetchall() histories_dict = {} for history in histories: histories_dict[(history['product_id'], history['company_id'])] = history['cost'] for line in res: inv_value = 0.0 lines = group_lines.get(str(line.get('__domain', []))) for line_id in lines: line_rec = lines_dict[line_id] product = products_dict[line_rec['product_id']] if product['cost_method'] == 'real': price = line_rec['price_unit_on_quant'] else: price = histories_dict.get( (product['id'], line_rec['company_id']), 0.0) inv_value += price * line_rec['quantity'] line['inventory_value'] = inv_value return res def _get_inventory_value(self, cr, uid, ids, name, attr, context=None): if context is None: context = {} date = context.get('history_date') product_obj = self.pool.get("product.product") res = {} for line in self.browse(cr, uid, ids, context=context): if line.product_id.cost_method == 'real': res[line.id] = line.quantity * line.price_unit_on_quant else: res[line.id] = line.quantity * product_obj.get_history_price( cr, uid, line.product_id.id, line.company_id.id, date=date, context=context) return res _columns = { 'move_id': fields.many2one('stock.move', 'Stock Move', required=True), 'location_id': fields.many2one('stock.location', 'Location', required=True), 'company_id': fields.many2one('res.company', 'Company'), 'product_id': fields.many2one('product.product', 'Product', required=True), 'product_categ_id': fields.many2one('product.category', 'Product Category', required=True), 'quantity': fields.float('Product Quantity'), 'date': fields.datetime('Operation Date'), 'price_unit_on_quant': fields.float('Value'), 'inventory_value': fields.function(_get_inventory_value, string="Inventory Value", type='float', readonly=True), 'source': fields.char('Source'), 'product_template_id': fields.many2one('product.template', 'Product Template', required=True), 'serial_number': fields.char('Serial Number', required=True), } def init(self, cr): tools.drop_view_if_exists(cr, 'stock_history') cr.execute(""" CREATE OR REPLACE VIEW stock_history AS ( SELECT MIN(id) as id, move_id, location_id, company_id, product_id, product_categ_id, product_template_id, SUM(quantity) as quantity, date, price_unit_on_quant, source, serial_number FROM ((SELECT stock_move.id::text || '-' || quant.id::text AS id, quant.id AS quant_id, stock_move.id AS move_id, dest_location.id AS location_id, dest_location.company_id AS company_id, stock_move.product_id AS product_id, product_template.id AS product_template_id, product_template.categ_id AS product_categ_id, quant.qty AS quantity, stock_move.date AS date, quant.cost as price_unit_on_quant, stock_move.origin AS source, stock_production_lot.name AS serial_number FROM stock_quant as quant LEFT JOIN stock_quant_move_rel ON stock_quant_move_rel.quant_id = quant.id LEFT JOIN stock_move ON stock_move.id = stock_quant_move_rel.move_id LEFT JOIN stock_production_lot ON stock_production_lot.id = quant.lot_id LEFT JOIN stock_location dest_location ON stock_move.location_dest_id = dest_location.id LEFT JOIN stock_location source_location ON stock_move.location_id = source_location.id LEFT JOIN product_product ON product_product.id = stock_move.product_id LEFT JOIN product_template ON product_template.id = product_product.product_tmpl_id WHERE quant.qty>0 AND stock_move.state = 'done' AND dest_location.usage in ('internal', 'transit') AND ( (source_location.company_id is null and dest_location.company_id is not null) or (source_location.company_id is not null and dest_location.company_id is null) or source_location.company_id != dest_location.company_id or source_location.usage not in ('internal', 'transit')) ) UNION (SELECT '-' || stock_move.id::text || '-' || quant.id::text AS id, quant.id AS quant_id, stock_move.id AS move_id, source_location.id AS location_id, source_location.company_id AS company_id, stock_move.product_id AS product_id, product_template.id AS product_template_id, product_template.categ_id AS product_categ_id, - quant.qty AS quantity, stock_move.date AS date, quant.cost as price_unit_on_quant, stock_move.origin AS source, stock_production_lot.name AS serial_number FROM stock_quant as quant LEFT JOIN stock_quant_move_rel ON stock_quant_move_rel.quant_id = quant.id LEFT JOIN stock_move ON stock_move.id = stock_quant_move_rel.move_id LEFT JOIN stock_production_lot ON stock_production_lot.id = quant.lot_id LEFT JOIN stock_location source_location ON stock_move.location_id = source_location.id LEFT JOIN stock_location dest_location ON stock_move.location_dest_id = dest_location.id LEFT JOIN product_product ON product_product.id = stock_move.product_id LEFT JOIN product_template ON product_template.id = product_product.product_tmpl_id WHERE quant.qty>0 AND stock_move.state = 'done' AND source_location.usage in ('internal', 'transit') AND ( (dest_location.company_id is null and source_location.company_id is not null) or (dest_location.company_id is not null and source_location.company_id is null) or dest_location.company_id != source_location.company_id or dest_location.usage not in ('internal', 'transit')) )) AS foo GROUP BY move_id, location_id, company_id, product_id, product_categ_id, date, price_unit_on_quant, source, product_template_id, serial_number )""")
class ProjectCompletionReport(osv.Model): """Project Completion Report""" _name = "project.completion.report" _auto = False _description = "Project Completion Report" _rec_name = 'activity_name' _columns = { 'id': fields.integer('Id', readonly=True), 'activity_type': fields.selection([ ('task', 'Task'), ('issue', 'Issue'), ], 'Type', readonly=True, help="Type is used to separate Tasks and Issues"), 'hours': fields.float('Time spent', digits=(16, 2), readonly=True, help="Time spent on timesheet"), 'user_id': fields.many2one('res.users', 'User', readonly=True), 'project_id': fields.many2one('project.project', 'Project', readonly=True), 'project_state': fields.char('State', readonly=True, help="Project State"), 'activity_stage_id': fields.many2one('project.task.type', 'Stage', readonly=True, help="Activity Stage"), 'account_id': fields.many2one('account.analytic.account', 'Analytic account', readonly=True), 'activity_id': fields.char('Activity id', readonly=True, help="Task id or Issue id"), 'activity_name': fields.char('Activity name', readonly=True, help="Task name or Issue name"), 'planned_hours': fields.float('Init. time', digits=(16, 2), readonly=True, help="Initial time"), 'remaining_hours': fields.float('Remain. time', digits=(16, 2), readonly=True, help="Remaining time"), 'br_id': fields.many2one('business.requirement', 'Bus. requ.', readonly=True, help="Business requirement"), 'partner_id': fields.many2one('res.partner', 'Customer', readonly=True), 'project_categ_id': fields.many2one('project.project.category', 'Project Cat.', readonly=True, help="Project Category"), } def init(self, cr): """ Project Completion Report @param cr: the current row, from the database cursor """ tools.drop_view_if_exists(cr, 'project_completion_report') cr.execute(""" CREATE OR REPLACE VIEW project_completion_report AS ( SELECT row_number() OVER (ORDER BY q.activity_id) AS id, q.* FROM ( ( SELECT 'task' AS activity_type, SUM(al.unit_amount) AS hours, t.user_id, p.id AS project_id, p.state AS project_state, t.stage_id AS activity_stage_id, a.id AS account_id, t.id AS activity_id, t.name AS activity_name, t.planned_hours, t.remaining_hours, b.id AS br_id, a.partner_id, p.project_categ_id FROM project_project p -- Link with the analytic account INNER JOIN account_analytic_account a ON a.id = p.analytic_account_id -- Link with the task INNER JOIN project_task t ON t.project_id = p.id -- Link with the timesheet LEFT OUTER JOIN project_task_work tw ON tw.task_id = t.id LEFT OUTER JOIN hr_analytic_timesheet ts ON ts.id = tw.hr_analytic_timesheet_id LEFT OUTER JOIN account_analytic_line al ON al.id = ts.line_id -- Link with the BR LEFT OUTER JOIN business_requirement b ON b.linked_project = p.id GROUP BY t.id, p.id, a.id, b.id ) UNION ( SELECT 'issue' AS activity_type, SUM(al.unit_amount) AS hours, i.user_id, p.id AS project_id, p.state AS project_state, i.stage_id AS activity_stage_id, a.id AS account_id, i.id AS activity_id, i.name AS activity_name, NULL AS planned_hours, NULL AS remaining_hours, b.id AS br_id, a.partner_id, p.project_categ_id FROM project_project p -- Link with the analytic account INNER JOIN account_analytic_account a ON a.id = p.analytic_account_id -- Link with the issue INNER JOIN project_issue i ON i.project_id = p.id -- Link with the timesheet LEFT OUTER JOIN hr_analytic_timesheet ts ON ts.issue_id = i.id LEFT OUTER JOIN account_analytic_line al ON al.id = ts.line_id -- Link with the BR LEFT OUTER JOIN business_requirement b ON b.linked_project = p.id GROUP BY i.id, p.id, a.id, b.id ) ) AS q )""")
class purchase_advance_payment_inv(osv.osv_memory): _name = "purchase.advance.payment.inv" _description = "Purchase Advance Payment Invoice" _columns = { 'line_percent': fields.float( 'Installment', digits_compute=dp.get_precision('Account'), help="The % of installment to be used to " "calculate the quantity to invoice"), } _defaults = { 'amount': 0.0, } def create_invoices(self, cr, uid, ids, context=None): wizard = self.browse(cr, uid, ids[0], context) # Additional case, Line Percentage if wizard.line_percent: # Getting PO Line IDs of this PO purchase_obj = self.pool.get('purchase.order') purchase_ids = context.get('active_ids', []) order = purchase_obj.browse(cr, uid, purchase_ids[0]) if order.invoiced_rate + wizard.line_percent > 100: raise osv.except_osv( _('Warning!'), _('This percentage is too high, ' 'it make overall invoiced rate exceed 100%!')) order_line_ids = [] for order_line in order.order_line: order_line_ids.append(order_line.id) # Assign them into active_ids context.update({'active_ids': order_line_ids}) context.update({'line_percent': wizard.line_percent}) purchase_order_line_make_invoice_obj = self.pool.get( 'purchase.order.line_invoice') res = purchase_order_line_make_invoice_obj.makeInvoices( cr, uid, ids, context=context) if not context.get('open_invoices', False): return {'type': 'ir.actions.act_window_close'} return res return super(purchase_advance_payment_inv, self).create_invoices( cr, uid, ids, context=context) def open_invoices(self, cr, uid, ids, invoice_ids, context=None): """ open a view on one of the given invoice_ids """ ir_model_data = self.pool.get('ir.model.data') form_res = ir_model_data.get_object_reference( cr, uid, 'account', 'invoice_supplier_form') form_id = form_res and form_res[1] or False tree_res = ir_model_data.get_object_reference( cr, uid, 'account', 'invoice_tree') tree_id = tree_res and tree_res[1] or False return { 'name': _('Advance Invoice'), 'view_type': 'form', 'view_mode': 'form,tree', 'res_model': 'account.invoice', 'res_id': invoice_ids[0], 'view_id': False, 'views': [(form_id, 'form'), (tree_id, 'tree')], 'context': "{'type': 'in_invoice'}", 'type': 'ir.actions.act_window', }
class LoungeOrderInternationalReport(osv.osv): _name = "report.lounge.order.international" _description = "Lounge Orders International" _auto = False _order = 'booking_from_date asc' _columns = { 'partner_id': fields.many2one('res.partner', 'Customer Name', readonly=True), 'lounge_reference': fields.char(string='Track No', readonly=True), 'date_order': fields.date(string='Order Date', readonly=True), 'booking_from_date': fields.datetime(string='Booking From', readonly=True), 'booking_to_date': fields.datetime(string='Booking To', readonly=True), 'company_type': fields.char(string='Customer Type', readonly=True), 'flight_type': fields.char(string='Flight Type', readonly=True), 'flight_number': fields.char(string='Flight No', readonly=True), 'service_01': fields.char(string='Service 1', readonly=True), 'service_02': fields.char(string='Service 2', readonly=True), 'service_03': fields.char(string='Service 3', readonly=True), 'payment_method': fields.char(string='Type', readonly=True), 'grandtotal': fields.float('Grand Total', readonly=True), 'payment_name': fields.char('Payment', readonly=True), 'total_pax': fields.integer('No.Pax', readonly=True), } _defaults = {'total_pax': 1} def init(self, cr): tools.drop_view_if_exists(cr, 'report_lounge_order_international') cr.execute(""" CREATE OR REPLACE VIEW report_lounge_order_international AS ( SELECT MIN(lo.id) AS id, lo.partner_id AS partner_id, lo.lounge_reference AS lounge_reference, to_char(lo.date_order, 'YYYY-MM-DD') AS date_order, lo.booking_from_date AS booking_from_date, lo.booking_to_date AS booking_to_date, CASE WHEN rp.company_type='company' THEN 'Company' ELSE 'Individual' END AS company_type, CASE WHEN lo.flight_type='international' THEN 'International' ELSE 'Domestic' END AS flight_type, lo.flight_number AS flight_number, lo.service_01 as service_01, lo.service_02 as service_02, lo.service_03 as service_03, CASE WHEN aj.type='cash' THEN 'Cash' ELSE 'Card' END AS payment_method, SUM(absl.amount) as grandtotal, aj.name AS payment_name, lo.total_pax AS total_pax FROM lounge_order AS lo LEFT JOIN res_partner AS rp ON rp.id = lo.partner_id LEFT JOIN account_bank_statement_line AS absl ON absl.lounge_statement_id = lo.id LEFT JOIN account_journal AS aj ON aj.id = absl.journal_id WHERE lo.state IN ('paid','invoice') AND lo.flight_type = 'international' GROUP BY lo.id,rp.id,aj.id ) """)
def _qty_all_2(self, cr, uid, ids, field_name, arg, context=None): result = {} for line in self.browse(cr, uid, ids, context=context): qty = line.qty2_2 uom = line.uom_id.factor_inv qty_all = round(qty*uom,3) result[line.id] = qty_all return result _columns = { 'name' : fields.char('Name', required=True), 'partner_id' : fields.many2one('res.partner','Principle',domain=[('supplier','=',True)],required=True), 'product_id' : fields.many2one('product.product','Bonus Product'), 'qty_2' : fields.float('Bonus Qty2', digits_compute=dp.get_precision('Product Unit of Measure')), 'qty' : fields.function(_qty_all_1,type="float",string='Bonus Qty',digits_compute=dp.get_precision('Product Unit of Measure')), 'uom_id' : fields.many2one('product.uom','UoM',required=True), 'uom_id2' : fields.many2one('product.uom','UoM',required=True), 'value' : fields.float('Price Value',domain=[('is_percent','=',False)]), 'per_product' : fields.boolean('Per Product'), 'persentase' : fields.float('Percent Value', digits_compute= dp.get_precision('Discount'),domain=[('is_percent','=',True)]), 'multi' : fields.boolean('Multiples'), 'is_active' : fields.boolean('Active?'), 'date_from' : fields.date('Start Date', required=True), 'date_to' : fields.date('End Date', required=True), 'condition_ids' : fields.one2many('master.condition','discount_id','Value Condition'), 'condition2_ids' : fields.one2many('master.condition2','discount_id','Product Condition'), 'condition3_ids' : fields.one2many('master.condition3','discount_id','Product Condition 2'), 'condition4_ids' : fields.one2many('master.condition4','discount_id','Product Condition 3'), 'condition5_ids' : fields.one2many('master.condition5','discount_id','Product Condition 4'),
class car_maintenance_request(osv.Model): _name = "car.maintenance.request" _description = 'Car Maintenance Request' def create(self, cr, user, vals, context=None): """ Method that creates a new sequence entry as a name for each new car maintenance request. @param vals: Dictionary of the entered data @return: Super create method """ if ('name' not in vals) or (vals.get('name') == '/'): vals['name'] = self.pool.get('ir.sequence').get( cr, user, 'car.maintenance.request') return super(car_maintenance_request, self).create(cr, user, vals, context) def _amount_all(self, cr, uid, ids, field_name, arg, context={}): """ Functional field function that calculates the total cost of all faults. @param field_name: list contains name of fields that call this method @param arg: extra arguement @return: Dictionary of values """ res = {} for record in self.browse(cr, uid, ids, context=context): val = 0.0 for line in record.faults: val += line.price_subtotal res[record.id] = val return res MAINTENANCE_TYPE_SELECTION = [ ('regular', 'Regular'), ('emergency', 'Emergency'), ('other', 'Other'), ] STATE_SELECTION = [ ('draft', 'Draft'), ('confirmed_d', 'Waiting for requesting party manager To approve'), ('confirmed_gd', 'Waiting for department manager to confirm '), ('approved_of', 'Waiting for admin affairs Service Manager'), # ('approved_of2', 'Waiting for admin affairs Service Manager'), ('officer_of', 'Waiting for admin affairs officer'), ('confirmed_gm', 'Waiting for admin affairs general manager to confirm'), ('approved', 'Waiting for admin affairs manager to approve'), ('execute', 'Waiting for maintenance engineer to execute '), ('check', 'Waiting for the completion of maintenance'), ('done', 'Done'), ('cancel', 'Cancel'), ] PAYMENT_SELECTION = [ ('voucher', 'Voucher'), ('enrich', 'Enrich'), ] _order = "name desc" _columns = { 'name': fields.char('Reference', size=64, required=True, select=True, readonly=True, help="unique number of the car maintenance "), 'date': fields.date( 'Request Date', required=True, readonly=True, ), #'department_id': fields.related('car_id', 'department_id', type='many2one', relation='hr.department',store=True, string='Department',readonly=True,states={'draft':[('readonly',False)],'confirmed_d':[('readonly',False)],'confirmed_gd':[('readonly',False)],}), 'department_id': fields.many2one('hr.department', 'Department', states={ 'approved': [('readonly', True)], 'approved_of': [('readonly', True)], 'execute': [('readonly', True)], 'check': [('readonly', True)], 'done': [('readonly', True)], 'cancel': [('readonly', True)] }), 'partner_id': fields.many2one('res.partner', 'Partner'), 'car_id': fields.many2one('fleet.vehicle', 'Car Name', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'confirmed_gd': [('readonly', False)], }), # 'category_id': fields.many2one('maintenance.category', 'Car Type'), 'car_number': fields.related('car_id', 'license_plate', type='char', relation='fleet.vehicle', string='Car Number', readonly=True), 'driver': fields.related('car_id', 'employee_id', type='many2one', relation='hr.employee', string='Driver', required=False, readonly=True), 'maintenance_date': fields.date('Maintenance Date', required=True, states={ 'done': [('readonly', True)], 'cancel': [('readonly', True)] }), 'base_mileage': fields.related('car_id', 'cmil', type='float', relation='fleet.vehicle', string='Current Mileage', readonly=True, help="The last recorded mileage"), 'next_mileage': fields.float('Next Mileage', digits=(16, 3), help="The next mileage", readonly=True, states={ 'draft': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'confirmed_gd': [('readonly', False)], }), 'maintenance_type': fields.selection(MAINTENANCE_TYPE_SELECTION, 'Maintenance Type', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'confirmed_gd': [('readonly', False)], }), 'notes': fields.text('Notes', size=256, readonly=True, states={ 'draft': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'confirmed_gd': [('readonly', False)], }), 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True), 'faults': fields.one2many('car.faults', 'fault_id', 'Car Faults', readonly=True, states={ 'draft': [('readonly', False)], 'execute': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'check': [('readonly', False)], 'officer_of': [('readonly', False)], }), 'total_amount': fields.function(_amount_all, method=True, digits_compute=dp.get_precision('Account'), string='Amount', store=True), 'state': fields.selection(STATE_SELECTION, 'State', readonly=True, select=True), 'user_id': fields.many2one('res.users', 'Responsible', readonly=True), 'voucher_no': fields.many2one('account.voucher', 'Voucher Number', readonly=True), 'allowance_computed': fields.boolean('Allowance Computed', ), 'next_maintenance_date': fields.date('Next Maintenance Date', states={ 'done': [('readonly', True)], 'cancel': [('readonly', True)] }), 'start_maintenance_date': fields.date('Start Maintenance Date', states={ 'done': [('readonly', True)], 'cancel': [('readonly', True)] }), 'end_maintenance_date': fields.date('End Maintenance Date', states={ 'done': [('readonly', True)], 'cancel': [('readonly', True)] }), 'payment_selection': fields.selection(PAYMENT_SELECTION, 'Payment', readonly=True, states={'check': [('readonly', False)]}, select=True), 'enrich_category': fields.many2one('payment.enrich', 'Enrich', readonly=True, states={'check': [('readonly', False)]}), } _sql_constraints = [ ('name_uniq', 'unique(name)', 'car maintenance reference must be unique !'), ] _defaults = { 'name': lambda self, cr, uid, context: '/', 'date': lambda *a: time.strftime('%Y-%m-%d'), 'company_id': lambda self, cr, uid, c: self.pool.get('res.company'). _company_default_get(cr, uid, 'car.maintenance.request', context=c), 'state': 'draft', 'user_id': lambda self, cr, uid, context: uid, 'allowance_computed': lambda *a: 0, } """ Workflow Functions""" def confirmed_d(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'confirmed_d'. @return: Boolean True """ #for record in self.browse(cr, uid, ids): #if not record.faults: #raise orm.except_orm(_('No Faults !'), _('Please Fault Item Details ..')) self.write(cr, uid, ids, {'state': 'confirmed_d'}) return True def confirmed_gd(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'confirmed_gd'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'confirmed_gd'}) return True def is_emergency(self, cr, uid, ids, context=None): """ Workflow method that checks wether the maintenance request is for emergency or not. @return: Boolean True Or False """ for record in self.browse(cr, uid, ids): if record.maintenance_type != "emergency": return False return True def is_roof(self, cr, uid, ids, context=None): """ Workflow method that checks wether the amount of maintenance request has a financial roof or not . @return: Boolean True Or False """ affairs_model_obj = self.pool.get('admin.affairs.model') payment_roof_obj = self.pool.get('admin.affaris.payment.roof') for record in self.browse(cr, uid, ids): if record.maintenance_type == "emergency": affairs_model_ids = affairs_model_obj.search( cr, uid, [('model', '=', 'car.maintenance')], context=context) if not affairs_model_ids: return True payment_roof_ids = payment_roof_obj.search( cr, uid, [('model_id', '=', affairs_model_ids[0]), ('name', '=', 'service')], context=context) affairs_payment = payment_roof_obj.browse(cr, uid, payment_roof_ids[0], context=context) if record.total_amount > affairs_payment.cost_to: return False return True def is_regular(self, cr, uid, ids, context=None): """ Workflow method that checks wether the maintenance type is regular or not . @return: Boolean True Or False """ for record in self.browse(cr, uid, ids): if record.maintenance_type != "regular": return False return True def confirmed_gm(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'confirmed_gm'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'confirmed_gm'}, context=context) return True def approved(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'approved'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'approved'}, context=context) return True def approved_of(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'approved_of'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'approved_of'}, context=context) return True """def approved_of2(self,cr,uid,ids,context=None): self.write(cr, uid, ids, {'state':'approved_of2'},context=context) return True""" def officer_of(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'officer_of'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'officer_of'}, context=context) return True def execute(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'execute'. @return: Boolean True """ self.write(cr, uid, ids, {'state': 'execute'}, context=context) return True def check(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'check' and checks the Faults have been entered and that it has prices. @return: Boolean True """ payment_enrich_obj = self.pool.get('payment.enrich') payment_enrich_lines_obj = self.pool.get('payment.enrich.lines') for record in self.browse(cr, uid, ids): if not record.faults: raise osv.except_osv(_('No Faults !'), _('Please Fault Item Details ..')) if record.payment_selection == 'enrich': paid = (record.enrich_category.paid_amount + record.total_amount) residual = (record.enrich_category.residual_amount - record.total_amount) #enrich_payment_id = cr.execute("""update payment_enrich set paid_amount=%s , residual_amount=%s where id =%s""",(paid,residual,record.enrich_category.id)) #details = smart_str('Service Request No:'+record.name+'\n'+record.service_category.name) details = 'Car Maintenance No:' + record.name enrich_payment_lines_id = payment_enrich_lines_obj.create( cr, uid, { 'enrich_id': record.enrich_category.id, 'cost': record.total_amount, 'date': record.date, 'name': details, 'department_id': record.department_id.id, }, context=context) self.write(cr, uid, ids, {'allowance_computed': True}, context=context) elif record.payment_selection == 'voucher': self.write(cr, uid, ids, {'allowance_computed': False}, context=context) for fault in record.faults: fault.write({'added_by_supplier': False}) if fault.price_unit == 0.0: raise osv.except_osv( _('No Price !'), _('Please make sure you enter prices for all items')) self.write(cr, uid, ids, {'state': 'check'}, context=context) return True def done(self, cr, uid, ids, context=None): """ Workflow method that changes the state to 'done' and updates next_mileage of fleet vehicle. @return: Boolean True """ for record in self.browse(cr, uid, ids): self.pool.get('fleet.vehicle').write(cr, uid, [record.car_id.id], {'cmil': record.next_mileage}) self.write(cr, uid, ids, {'state': 'done'}, context=context) return True def modify_maintenance_request(self, cr, uid, ids, context=None): """ Method that deletes the old Maintenance request's workflow and creat a new one in the 'check' state. @return: Boolean True """ if not len(ids): return False wf_service = netsvc.LocalService("workflow") for s_id in ids: wf_service.trg_delete(uid, 'car.maintenance.request', s_id, cr) wf_service.trg_create(uid, 'car.maintenance.request', s_id, cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'draft', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'confirmed_d', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'confirmed_gd', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'approved_of', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'officer_of', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'confirmed_gm', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'approved', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'execute', cr) res = wf_service.trg_validate(uid, 'car.maintenance.request', s_id, 'check', cr) #self.write(cr, uid, s_id, {'state':'dept_confirm'}) return True def cancel(self, cr, uid, ids, notes='', context=None): """ Method changes state of To 'cancel' and write notes about the cancellation. @param notes: contains information of who & when cancelling the car maintenance request. @return: Boolean True """ notes = "" u = self.pool.get('res.users').browse(cr, uid, uid).name notes = notes + '\n' + 'Car Maintenance Request Cancelled at : ' + time.strftime( '%Y-%m-%d') + ' by ' + u self.write(cr, uid, ids, {'state': 'cancel', 'notes': notes}) return True def ir_action_cancel_draft(self, cr, uid, ids, context=None): """ Method resets the Car Maintenance Request record to 'draft' , deletes the old workflow and creates a new one. @return: Boolean True """ if not len(ids): return False wf_service = netsvc.LocalService("workflow") for s_id in ids: self.write(cr, uid, s_id, {'state': 'draft'}) wf_service.trg_delete(uid, 'car.maintenance.request', s_id, cr) wf_service.trg_create(uid, 'car.maintenance.request', s_id, cr) return True def unlink(self, cr, uid, ids, context=None): """ Method that overwrites unlink method to prevent the the deletion of Car Maintenance Request record not in 'draft' state. @return: Super unlink method """ stat = self.read(cr, uid, ids, ['state'], context=context) unlink_ids = [] for t in stat: if t['state'] in ('draft'): unlink_ids.append(t['id']) else: raise osv.except_osv( _('Invalid action !'), _('In order to delete a car maintenance request, \ you must first cancel it,and set to draft.')) return super(car_maintenance_request, self).unlink(self, cr, uid, unlink_ids, context=context) def create_financial_voucher(self, cr, uid, ids, context=None): """ Method that transfers the cost of maintenance to the voucher and creates a ratification for car's maintenance request . @return: Dictionary of values """ names = '' voucher_obj = self.pool.get('account.voucher') voucher_line_obj = self.pool.get('account.voucher.line') for request in self.browse(cr, uid, ids, context=context): for pro in request.faults: names += pro.name + '\n' notes = _( "Car Maintenance : %s \nMaintenance Type: %s.\nSpare Part: %s." ) % (request.name, request.maintenance_type, names) config_id = self.pool.get('admin_affairs.account').search( cr, uid, [('company_id', '=', request.company_id.id)], context=context) if not config_id: raise osv.except_osv( _('Invalid action !'), _('Please insert the Company Configruation Account For Car Maintenance' )) account_config = self.pool.get('admin_affairs.account').browse( cr, uid, config_id[0]) # Creating Voucher / Ratitication voucher_id = voucher_obj.create( cr, uid, { 'amount': request.total_amount, 'type': 'ratification', 'date': time.strftime('%Y-%m-%d'), 'partner_id': request.partner_id.id, 'department_id': request.department_id.id, 'journal_id': account_config.maintenance_jorunal_id.id, 'state': 'draft', 'notes': request.notes, 'narration': notes, }, context=context) voucher_line_dict = { 'voucher_id': voucher_id, 'account_id': account_config.maintenance_account_id.id, 'account_analytic_id': account_config.maintenance_analytic_id.id or request.department_id.analytic_account_id.id, 'amount': request.total_amount, 'type': 'dr', 'name': request.department_id.name, } voucher_line_obj.create(cr, uid, voucher_line_dict, context=context) #################### update workflow state############### voucher_state = 'draft' if record.company_id.affairs_voucher_state: voucher_state = record.company_id.affairs_voucher_state if voucher_id: wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'account.voucher', voucher_id, voucher_state, cr) voucher_obj.write( cr, uid, voucher_id, { 'type': 'ratification', 'ratification': True, 'state': voucher_state }, context) # Selecting Voucher Number / Refernece #voucher_number = voucher_obj.browse(cr,uid,voucher_id,context=context).number self.write(cr, uid, request.id, {'voucher_no': voucher_id}, context=context) return True
('cancelled', 'Cancelled') ], 'Shipping Status', readonly=True, help='The current status of the shipment'), 'trade_mark': fields.text('Trademarks AREA'), 'ship_message': fields.text('Message'), 'address_validate': fields.selection([ ('validate', 'Validate'), ('nonvalidate', 'No Validation') ], 'Address Validation', help=''' No Validation = No address validation. Validate = Fail on failed address validation. Defaults to validate. Note: Full address validation is not performed. Therefore, it is the responsibility of the Shipping Tool User to ensure the address entered is correct to avoid an address correction fee.'''), 'ship_description': fields.text('Description'), 'ship_from': fields.boolean('Ship From', help='Required if pickup location is different from the shipper\'s address..'), 'ship_from_tax_id_no': fields.char('Identification Number', size=30 , select=1), 'shipcharge': fields.float('Shipping Cost', readonly=True), 'ship_from_address': fields.many2one('res.partner', 'Ship From Address', size=30), # 'address': fields.many2one('res.partner', 'Ship From Address'), 'tot_order_weight': fields.related('sale_id', 'total_weight_net', type='float', relation='sale.order', string='Total Order Weight'), 'comm_inv': fields.boolean('Commercial Invoice'), 'cer_orig': fields.boolean('U.S. Certificate of Origin'), 'nafta_cer_orig': fields.boolean('NAFTA Certificate of Origin'), 'sed': fields.boolean('Shipper Export Declaration (SED)'), 'prod_option': fields.selection([ ('01', 'AVAILABLE TO CUSTOMS UPON REQUEST'), ('02', 'SAME AS EXPORTER'), ('03', 'ATTACHED LIST'), ('04', 'UNKNOWN'), (' ', ' ') ], 'Option'), 'prod_company': fields.char('CompanyName', size=256, help='Only applicable when producer option is empty or not present.'),
class car_faults(osv.Model): _name = "car.faults" _description = 'Type of Fault' def _amount_line(self, cr, uid, ids, field_name, arg, context=None): """ Functional field function that calculates the cost of each car fault line ( quantity*price ). @param field_name: List contains name of fields that call this method @param arg: Extra arguement @return: Dictionary of values """ context.update({'ids': ids}) res = {} if context is None: context = {} for line in self.browse(cr, uid, ids, context=context): price = line.price_unit * line.product_qty or 0.0 res[line.id] = price return res _columns = { 'name': fields.char( 'Name', size=64, select=True, ), 'product_id': fields.many2one('product.product', 'Item', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'execute': [('readonly', False)], 'check': [('readonly', False)], }), 'product_qty': fields.float('Item Quantity', required=True, digits=(16, 2), readonly=True, states={ 'draft': [('readonly', False)], 'execute': [('readonly', False)], 'check': [('readonly', False)], }), 'product_uom': fields.many2one('product.uom', 'Item UOM', readonly=True, states={ 'draft': [('readonly', False)], 'execute': [('readonly', False)], 'check': [('readonly', False)], }), 'fault_id': fields.many2one('car.maintenance.request', 'car maintenance request', ondelete='cascade'), 'price_unit': fields.float('Unit Price', digits_compute=dp.get_precision('Account'), readonly=True, store=True, states={ 'draft': [('readonly', False)], 'confirmed_d': [('readonly', False)], 'execute': [('readonly', False)], 'check': [('readonly', False)], 'officer_of': [('readonly', False)], }), 'price_subtotal': fields.function(_amount_line, method=True, string='Sub total', digits_compute=dp.get_precision('Account'), readonly=True, store=True), 'added_by_supplier': fields.boolean( 'Added by supplier', help= "By checking the Added by supplier field, you determine this product as adding by supplier", readonly=True, ), 'state': fields.related( 'fault_id', 'state', type='char', relation='car.maintenance.request', string=' State', readonly=True, ), 'notes': fields.text( 'Notes', size=256, ), } _sql_constraints = [ ('produc_uniq', 'unique(fuel_id,product_id)', 'Fault must be unique!'), ] _defaults = { 'product_qty': 1.0, 'added_by_supplier': True, 'state': 'draft', } def product_id_change(self, cr, uid, ids, product, context=None): """ Method that reads the default name and UOM of the given product id. @param product: Id of product @return: Dictionary of values """ if product: prod = self.pool.get('product.product').browse(cr, uid, product) return { 'value': { 'name': prod.name, 'product_uom': prod.uom_po_id.id } } #---------------------------------------- # Class car maintenance roof #---------------------------------------- #class car_maintenance_roof(osv.Model): """def _check_roof_cost(self, cr, uid, ids, context=None):
] def _get_size_usps(self, cr, uid, context=None): return [ ('REGULAR', 'Regular'), ('LARGE', 'Large'), ] _columns= { 'ship_company_code': fields.selection(_get_company_code, 'Ship Company', method=True, size=64), 'usps_service_type' : fields.selection(_get_service_type_usps, 'Service Type', size=100), 'usps_package_location' : fields.selection([ ('Front Door','Front Door'), ('Back Door','Back Door'), ('Side Door','Side Door'), ('Knock on Door/Ring Bell','Knock on Door/Ring Bell'), ('Mail Room','Mail Room'), ('Office','Office'), ('Reception','Reception'), ('In/At Mailbox','In/At Mailbox'), ('Other','Other'), ],'Package Location'), 'usps_first_class_mail_type' : fields.selection(_get_first_class_mail_type_usps, 'First Class Mail Type', size=50), 'usps_container' : fields.selection(_get_container_usps,'Container', size=100), 'usps_size' : fields.selection(_get_size_usps,'Size'), 'usps_length' : fields.float('Length'), 'usps_width' : fields.float('Width'), 'usps_height' : fields.float('Height'), 'usps_girth' : fields.float('Girth'), } shipping_rate_wizard() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class report_invoice_created(osv.osv): _name = "report.invoice.created" _description = "Report of Invoices Created within Last 15 days" _auto = False _columns = { 'name': fields.char('Description', readonly=True), 'type': fields.selection([ ('out_invoice', 'Customer Invoice'), ('in_invoice', 'Supplier Invoice'), ('out_refund', 'Customer Refund'), ('in_refund', 'Supplier Refund'), ], 'Type', readonly=True), 'number': fields.char('Invoice Number', readonly=True), 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True), 'amount_untaxed': fields.float('Untaxed', readonly=True), 'amount_total': fields.float('Total', readonly=True), 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True), 'date_invoice': fields.date('Invoice Date', readonly=True), 'date_due': fields.date('Due Date', readonly=True), 'residual': fields.float('Residual', readonly=True), 'state': fields.selection([('draft', 'Draft'), ('proforma', 'Pro-forma'), ('proforma2', 'Pro-forma'), ('open', 'Open'), ('paid', 'Done'), ('cancel', 'Cancelled')], 'Status', readonly=True), 'origin': fields.char( 'Source Document', readonly=True, help="Reference of the document that generated this invoice report." ), 'create_date': fields.datetime('Create Date', readonly=True) } _order = 'create_date' def init(self, cr): tools.drop_view_if_exists(cr, 'report_invoice_created') cr.execute("""create or replace view report_invoice_created as ( select inv.id as id, inv.name as name, inv.type as type, inv.number as number, inv.partner_id as partner_id, inv.amount_untaxed as amount_untaxed, inv.amount_total as amount_total, inv.currency_id as currency_id, inv.date_invoice as date_invoice, inv.date_due as date_due, inv.residual as residual, inv.state as state, inv.origin as origin, inv.create_date as create_date from account_invoice inv where (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') <= CURRENT_DATE) AND (to_date(to_char(inv.create_date, 'YYYY-MM-dd'),'YYYY-MM-dd') > (CURRENT_DATE-15)) )""")
class PaymentTransaction(osv.Model): """ Transaction Model. Each specific acquirer can extend the model by adding its own fields. Methods that can be added in an acquirer-specific implementation: - ``<name>_create``: method receiving values used when creating a new transaction and that returns a dictionary that will update those values. This method can be used to tweak some transaction values. Methods defined for convention, depending on your controllers: - ``<name>_form_feedback(self, cr, uid, data, context=None)``: method that handles the data coming from the acquirer after the transaction. It will generally receives data posted by the acquirer after the transaction. """ _name = 'payment.transaction' _description = 'Payment Transaction' _inherit = ['mail.thread'] _order = 'id desc' _rec_name = 'reference' _columns = { 'date_create': fields.datetime('Creation Date', readonly=True, required=True), 'date_validate': fields.datetime('Validation Date'), 'acquirer_id': fields.many2one( 'payment.acquirer', 'Acquirer', required=True, ), 'type': fields.selection( [('server2server', 'Server To Server'), ('form', 'Form')], string='Type', required=True), 'state': fields.selection( [('draft', 'Draft'), ('pending', 'Pending'), ('done', 'Done'), ('error', 'Error'), ('cancel', 'Canceled') ], 'Status', required=True, track_visiblity='onchange', copy=False), 'state_message': fields.text('Message', help='Field used to store error and/or validation messages for information'), # payment 'amount': fields.float('Amount', required=True, digits=(16, 2), track_visibility='always', help='Amount in cents'), 'fees': fields.float('Fees', digits=(16, 2), track_visibility='always', help='Fees amount; set by the system because depends on the acquirer'), 'currency_id': fields.many2one('res.currency', 'Currency', required=True), 'reference': fields.char('Order Reference', required=True), 'acquirer_reference': fields.char('Acquirer Order Reference', help='Reference of the TX as stored in the acquirer database'), # duplicate partner / transaction data to store the values at transaction time 'partner_id': fields.many2one('res.partner', 'Partner', track_visibility='onchange',), 'partner_name': fields.char('Partner Name'), 'partner_lang': fields.char('Lang'), 'partner_email': fields.char('Email'), 'partner_zip': fields.char('Zip'), 'partner_address': fields.char('Address'), 'partner_city': fields.char('City'), 'partner_country_id': fields.many2one('res.country', 'Country', required=True), 'partner_phone': fields.char('Phone'), 'partner_reference': fields.char('Partner Reference', help='Reference of the customer in the acquirer database'), } _sql_constraints = [ ('reference_uniq', 'UNIQUE(reference)', 'The payment transaction reference must be unique!'), ] _defaults = { 'date_create': fields.datetime.now, 'type': 'form', 'state': 'draft', 'partner_lang': 'en_US', } def create(self, cr, uid, values, context=None): Acquirer = self.pool['payment.acquirer'] if values.get('partner_id'): # @TDENOTE: not sure values.update(self.on_change_partner_id(cr, uid, None, values.get('partner_id'), context=context)['values']) # call custom create method if defined (i.e. ogone_create for ogone) if values.get('acquirer_id'): acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context) # compute fees custom_method_name = '%s_compute_fees' % acquirer.provider if hasattr(Acquirer, custom_method_name): fees = getattr(Acquirer, custom_method_name)( cr, uid, acquirer.id, values.get('amount', 0.0), values.get('currency_id'), values.get('country_id'), context=None) values['fees'] = float_round(fees, 2) # custom create custom_method_name = '%s_create' % acquirer.provider if hasattr(self, custom_method_name): values.update(getattr(self, custom_method_name)(cr, uid, values, context=context)) return super(PaymentTransaction, self).create(cr, uid, values, context=context) def on_change_partner_id(self, cr, uid, ids, partner_id, context=None): partner = None if partner_id: partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) return {'values': { 'partner_name': partner and partner.name or False, 'partner_lang': partner and partner.lang or 'en_US', 'partner_email': partner and partner.email or False, 'partner_zip': partner and partner.zip or False, 'partner_address': _partner_format_address(partner and partner.street or '', partner and partner.street2 or ''), 'partner_city': partner and partner.city or False, 'partner_country_id': partner and partner.country_id.id or False, 'partner_phone': partner and partner.phone or False, }} # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- def form_feedback(self, cr, uid, data, acquirer_name, context=None): invalid_parameters, tx = None, None tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name if hasattr(self, tx_find_method_name): tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) invalid_param_method_name = '_%s_form_get_invalid_parameters' % acquirer_name if hasattr(self, invalid_param_method_name): invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, tx, data, context=context) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (acquirer_name) for item in invalid_parameters: _error_message += '\t%s: received %s instead of %s\n' % (item[0], item[1], item[2]) _logger.error(_error_message) return False feedback_method_name = '_%s_form_validate' % acquirer_name if hasattr(self, feedback_method_name): return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) return True # -------------------------------------------------- # SERVER2SERVER RELATED METHODS # -------------------------------------------------- def s2s_create(self, cr, uid, values, cc_values, context=None): tx_id, tx_result = self.s2s_send(cr, uid, values, cc_values, context=context) self.s2s_feedback(cr, uid, tx_id, tx_result, context=context) return tx_id def s2s_send(self, cr, uid, values, cc_values, context=None): """ Create and send server-to-server transaction. :param dict values: transaction values :param dict cc_values: credit card values that are not stored into the payment.transaction object. Acquirers should handle receiving void or incorrect cc values. Should contain : - holder_name - number - cvc - expiry_date - brand - expiry_date_yy - expiry_date_mm """ tx_id, result = None, None if values.get('acquirer_id'): acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context) custom_method_name = '_%s_s2s_send' % acquirer.provider if hasattr(self, custom_method_name): tx_id, result = getattr(self, custom_method_name)(cr, uid, values, cc_values, context=context) if tx_id is None and result is None: tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context) return (tx_id, result) def s2s_feedback(self, cr, uid, tx_id, data, context=None): """ Handle the feedback of a server-to-server transaction. """ tx = self.browse(cr, uid, tx_id, context=context) invalid_parameters = None invalid_param_method_name = '_%s_s2s_get_invalid_parameters' % tx.acquirer_id.provider if hasattr(self, invalid_param_method_name): invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, tx, data, context=context) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (tx.acquirer_id.name) for item in invalid_parameters: _error_message += '\t%s: received %s instead of %s\n' % (item[0], item[1], item[2]) _logger.error(_error_message) return False feedback_method_name = '_%s_s2s_validate' % tx.acquirer_id.provider if hasattr(self, feedback_method_name): return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) return True def s2s_get_tx_status(self, cr, uid, tx_id, context=None): """ Get the tx status. """ tx = self.browse(cr, uid, tx_id, context=context) invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.provider if hasattr(self, invalid_param_method_name): return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context) return True
class delivery_route_out_wizard_line(osv.osv_memory): """ Movimientos de stock """ _name = "delivery.route.out.wizard.line" def action_done(self, cr, uid, ids, context=None): """ Prepara la carga al vehiculo de transportista """ print "*****PREPARANDO LA CARGA AL VEHICULO DE TRANSPORTISTA*****" route_id = False res_id = False move_obj = self.pool.get('delivery.route.out.move') # Recorre las lineas a confirmar para obtener el movimiento for line in self.browse(cr, uid, ids, context=context): if line.move_id: # Valida que haya cantidad disponible para hacer la entrega if line.product_qty > line.virtual_available: raise osv.except_osv( _('Error'), _("No hay producto disponible para surtir este pedido sobre la ruta la Ruta. (Producto: %s)" % (line.name, ))) print "****PONIENDO EL PRODUCTO COMO CARGADO EN LA CAMIONETA***" # Pone el producto como cargado en la camioneta move_obj.action_done(cr, uid, [line.move_id.id], context=context) route_id = line.route_id.id or False res_id = line.wizard_id.id or False # Revisa si hay movimientos pendientes move_ids = move_obj.search(cr, uid, [('route_id', '=', route_id), ('state', 'not in', ['cancel', 'done'])]) print "****MOVE_IDS****: ", move_ids if move_ids: # Va a la parte de Preparar embarque return { 'name': 'Preparar Embarque', 'view_type': 'form', 'view_mode': 'form', 'res_model': 'delivery.route.out.wizard', 'target': 'new', 'context': { 'default_route_id': route_id }, 'type': 'ir.actions.act_window', 'res_id': res_id } return self.pool.get('delivery.route').update_stock(cr, uid, [route_id], context=context) def _product_available(self, cr, uid, ids, name, arg, context=None): """ Retorna el producto disponible sobre la tienda """ product_obj = self.pool.get('product.product') res = {} if context is None: context = {} ctx = context.copy() ctx.update({ 'states': ('waiting', 'assigned', 'done'), 'what': ('in', 'out') }) #Recorre las lineas del producto for line in self.browse(cr, uid, ids, context=context): if not line.product_id: # Retorna 0 si no hay producto res[line.id] = 0.0 else: # Obtiene el id de la ubicacion origen if line.location_id: ctx['location'] = line.location_id.id # Asigna la stock virtual del producto a la linea del pedido de venta. stock = product_obj.get_product_available(cr, uid, [line.product_id.id], context=ctx) print "********STOCK******: ", stock res[line.id] = stock.get(line.product_id.id, 0.0) # Aparta la cantidad de la existencia a cargar al transportista if line.state != 'done': res[line.id] += line.product_qty return res _columns = { 'name': fields.char('Descripcion', size=128), 'wizard_id': fields.many2one('delivery.route.out.wizard', 'Wizard', ondelete="cascade"), 'move_id': fields.many2one('delivery.route.out.move', 'Movimiento Stock', ondelete="cascade", required=True), 'route_id': fields.many2one('delivery.route', 'Ruta'), 'product_id': fields.many2one('product.product', 'Producto'), 'product_qty': fields.float('Cantidad'), 'product_uom': fields.many2one('product.uom', 'Unidad de medida', ondelete="cascade"), 'location_id': fields.many2one('stock.location', 'Ubicacion origen', ondelete="set null"), 'state': fields.related('move_id', 'state', type="selection", selection=[('draft', 'Por cargar'), ('cancel', 'Cancelado'), ('done', 'Realizado')], string='Estado', select=True), 'virtual_available': fields.function(_product_available, type='float', string='Disponible'), }
cur_obj = self.pool.get('res.currency') #import pdb;pdb.set_trace() for line in self.browse(cr, uid, ids): #price = line.price_unit * (1-(line.discount or 0.0)/100.0) price = round(line.price_unit *line.quantity,3) # taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, partner=line.invoice_id.partner_id) taxes = tax_obj.compute_all(cr, uid, line.invoice_line_tax_id, price, line.quantity, product=line.product_id, partner=line.invoice_id.partner_id) #res[line.id] = taxes['total'] res[line.id] = price # if line.invoice_id: # cur = line.invoice_id.currency_id # res[line.id] = cur_obj.round(cr, uid, cur, res[line.id]) return res _columns = { 'quantity2': fields.float('Small Qty', digits_compute= dp.get_precision('Product Unit of Measure')), 'uom_id' : fields.many2one('product.uom', 'Small UoM', ondelete='set null', select=True,required=True), 'disc_tot': fields.float('Disc Total'), 'price_subtotal': fields.function(_amount_line, string='Amount', type="float", digits_compute= dp.get_precision('Account'), store=True), 'qty_func': fields.function(_get_tot_qty,string='Qty Tot'), 'qty': fields.float('Qty', digits_compute= dp.get_precision('Product Unit of Measure')), 'quantity': fields.function(_get_tot_qty,string='Quantity',type="float", digits_compute= dp.get_precision('Product Unit of Measure'), required=True), 'price_unit2': fields.float('Price Unit 2'), 'quantity3' : fields.float('Quantity PO'), } _defaults = { 'uom_id' : _get_uom_id, }
class wizard_payment_wht_specification_line(orm.TransientModel): _name = 'wizard.payment.wht.specification.line' _description = 'Wizard Payment Wht Specification Line' _columns = { 'state': fields.selection([ ('confirmed', 'Confirmed'), ('selected', 'Selected')], 'State'), 'move_line_id': fields.many2one('account.move.line', 'Move Line'), 'account_id': fields.many2one('account.account', 'Account'), 'partner_id': fields.many2one('res.partner', 'Supplier'), 'payment_specification_id': fields.many2one('wizard.payment.wht.specification', 'Payment Specification', ondelete="cascade", required=True), 'amount': fields.float('Amount') } def get_wizard_confirmed_filters(self, context=None): filters = [] t_maturity = context.get('default_maturity', None) if(t_maturity): f = ('date_maturity', '<=', t_maturity) filters.append(f) filters.append(('wht_state', '=', 'confirmed')) if(len(filters) > 1): filters.insert(0, '&') return filters def get_wizard_selected_filters(self, context=None): filters = [] t_maturity = context.get('default_maturity', None) if(t_maturity): f = ('date_maturity', '<=', t_maturity) filters.append(f) filters.append(('wht_state', '=', 'selected')) if(len(filters) > 1): filters.insert(0, '&') return filters def set_payment_lines(self, cr, uid, context=None): t_lines = [] t_limit = 50 t_page = context.get('default_actual_page', None) wizard_obj = self.pool.get('wizard.payment.wht.specification') wizard_wht_obj = self.pool.get('wizard.payment.wht') account_move_line_obj = self.pool.get('account.move.line') t_filters = self.get_wizard_confirmed_filters(context) t_total_pages = wizard_wht_obj.get_total_pages(cr, uid, t_filters, t_limit) if(t_page > t_total_pages or t_total_pages == 1): t_page = t_total_pages context.update({ 'default_actual_page': t_page, }) t_offset = t_limit * (t_page - 1) res_id = wizard_obj.create(cr, uid, { 'total_pages': t_total_pages, }, context) account_move_line_ids = account_move_line_obj.search(cr, uid, t_filters, order='id', limit=t_limit, offset=t_offset, context=context) for line in account_move_line_obj.browse(cr, uid, account_move_line_ids): t_move_line_id = line.id t_state = line.wht_state t_lines.append((0, 0, { 'state': t_state, 'move_line_id': t_move_line_id, 'partner_id': line.partner_id.id, 'account_id': line.account_id.id, 'payment_specification_id': res_id, 'amount': line.credit })) self.pool.get('wizard.payment.wht.specification').write(cr, uid, [res_id], {'confirmed_ids': t_lines, }) t_lines = [] t_filters = [] t_filters = self.get_wizard_selected_filters(context) account_move_line_ids = account_move_line_obj.search(cr, uid, t_filters, order='id', context=context) for line in account_move_line_obj.browse(cr, uid, account_move_line_ids): t_move_line_id = line.id t_state = line.wht_state t_lines.append((0, 0, { 'state': t_state, 'move_line_id': t_move_line_id, 'partner_id': line.partner_id.id, 'account_id': line.account_id.id, 'payment_specification_id': res_id, 'amount': line.credit })) self.pool.get('wizard.payment.wht.specification').write(cr, uid, [res_id], {'selected_ids': t_lines, }) return res_id def move_draft_forward(self, cr, uid, ids, context=None): if context is None: context = {} return self.move_draft(1, cr, uid, ids, context) def move_draft_backward(self, cr, uid, ids, context=None): if context is None: context = {} return self.move_draft(0, cr, uid, ids, context) def move_draft(self, fb, cr, uid, ids, context=None): if context is None: context = {} line_id = context.get('line_id', None) data = self.browse(cr, uid, line_id, context=context) t_journal = data.payment_specification_id.journal_id.id t_maturity = data.payment_specification_id.maturity t_page = data.payment_specification_id.actual_page t_state = 'confirmed' if fb: t_state = 'selected' draft_obj = self.pool.get('account.move.line') t_move_id = data.move_line_id.id draft_obj.write(cr, uid, [t_move_id], { 'wht_state': t_state, }) # t_move = data.move_line_id.move_id context.update({ 'default_journal_id': t_journal, 'default_maturity': t_maturity, 'default_actual_page': t_page, }) res_id = self.set_payment_lines(cr, uid, context) mod_obj = self.pool.get('ir.model.data') result = mod_obj.get_object_reference(cr, uid, 'account_voucher_makeover', 'wizard_payment_wht_specification_view') view_id = result and result[1] or False return { 'name': _("Wizard Wht Payment Specification"), 'view_type': 'form', 'view_mode': 'form', 'res_model': 'wizard.payment.wht.specification', 'type': 'ir.actions.act_window', 'res_id': res_id, 'view_id': view_id, 'context': context, 'target': 'inlineview', }
class product_product(orm.Model): _inherit = "product.product" _columns = { 'date_percentage': fields.float('Date percentage'), }
class sale_order(osv.osv): _inherit = "sale.order" def _product_margin(self, cr, uid, ids, field_name, arg, context=None): result = {} for sale in self.browse(cr, uid, ids, context=context): result[sale.id] = 0.0 for line in sale.order_line: result[sale.id] += line.margin or 0.0 if sale.amount_untaxed > 0: sale.write( {'margin_perc': result[sale.id] / sale.amount_untaxed}) else: sale.write({'margin_perc': 0.0}) return result # def _product_margin_perc(self, cr, uid, ids, field_name, arg, context=None): # result = {} # margin_order = {} # for sale in self.browse(cr, uid, ids, context=context): # margin_order[sale.id] = 0.0 # for line in sale.order_line: # margin_order[sale.id] += line.margin or 0.0 # if sale.amount_untaxed > 0: # result[sale.id] = margin_order[sale.id] / sale.amount_untaxed # else: # result[sale.id] = 0.0 # #result = 0.0 # return result def _get_order(self, cr, uid, ids, context=None): result = {} for line in self.pool.get('sale.order.line').browse(cr, uid, ids, context=context): result[line.order_id.id] = True return result.keys() _columns = { 'margin': fields.function( _product_margin, string='Margin', help= "It gives profitability by calculating the difference between the Unit Price and the cost price.", store={ 'sale.order.line': (_get_order, ['margin', 'purchase_price'], 20), 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 20), }), 'margin_perc': fields.float( string='Margin Perc.', help= "It gives profitability by calculating the difference between the Unit Price and the cost price." ) # store={ # 'margin_perc': fields.function(_product_margin_perc, string='Margin Perc.', help="It gives profitability by calculating the difference between the Unit Price and the cost price.", store={ # 'sale.order.line': (_get_order, ['margin', 'purchase_price'], 20), # 'sale.order': (lambda self, cr, uid, ids, c={}: ids, ['order_line'], 20), # }), } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class account_config_settings(osv.osv_memory): _name = 'account.config.settings' _inherit = 'res.config.settings' _columns = { 'company_id': fields.many2one('res.company', 'Company', required=True), 'has_default_company': fields.boolean('Has default company', readonly=True), 'expects_chart_of_accounts': fields.related('company_id', 'expects_chart_of_accounts', type='boolean', string='This company has its own chart of accounts', help="""Check this box if this company is a legal entity."""), 'currency_id': fields.related('company_id', 'currency_id', type='many2one', relation='res.currency', required=True, string='Default company currency', help="Main currency of the company."), 'paypal_account': fields.related('company_id', 'paypal_account', type='char', size=128, string='Paypal account', help="Paypal account (email) for receiving online payments (credit card, etc.) If you set a paypal account, the customer will be able to pay your invoices or quotations with a button \"Pay with Paypal\" in automated emails or through the Odoo portal."), 'company_footer': fields.related('company_id', 'rml_footer', type='text', readonly=True, string='Bank accounts footer preview', help="Bank accounts as printed in the footer of each printed document"), 'has_chart_of_accounts': fields.boolean('Company has a chart of accounts'), 'chart_template_id': fields.many2one('account.chart.template', 'Template', domain="[('visible','=', True)]"), 'code_digits': fields.integer('# of Digits', help="No. of digits to use for account code"), 'tax_calculation_rounding_method': fields.related('company_id', 'tax_calculation_rounding_method', type='selection', selection=[ ('round_per_line', 'Round per line'), ('round_globally', 'Round globally'), ], string='Tax calculation rounding method', help="If you select 'Round per line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."), 'sale_tax': fields.many2one("account.tax.template", "Default sale tax"), 'purchase_tax': fields.many2one("account.tax.template", "Default purchase tax"), 'sale_tax_rate': fields.float('Sales tax (%)'), 'purchase_tax_rate': fields.float('Purchase tax (%)'), 'complete_tax_set': fields.boolean('Complete set of taxes', help='This boolean helps you to choose if you want to propose to the user to encode the sales and purchase rates or use the usual m2o fields. This last choice assumes that the set of tax defined for the chosen template is complete'), 'has_fiscal_year': fields.boolean('Company has a fiscal year'), 'date_start': fields.date('Start date', required=True), 'date_stop': fields.date('End date', required=True), 'period': fields.selection([('month', 'Monthly'), ('3months','3 Monthly')], 'Periods', required=True), 'sale_journal_id': fields.many2one('account.journal', 'Sale journal'), 'sale_sequence_prefix': fields.related('sale_journal_id', 'sequence_id', 'prefix', type='char', string='Invoice sequence'), 'sale_sequence_next': fields.related('sale_journal_id', 'sequence_id', 'number_next', type='integer', string='Next invoice number'), 'sale_refund_journal_id': fields.many2one('account.journal', 'Sale refund journal'), 'sale_refund_sequence_prefix': fields.related('sale_refund_journal_id', 'sequence_id', 'prefix', type='char', string='Credit note sequence'), 'sale_refund_sequence_next': fields.related('sale_refund_journal_id', 'sequence_id', 'number_next', type='integer', string='Next credit note number'), 'purchase_journal_id': fields.many2one('account.journal', 'Purchase journal'), 'purchase_sequence_prefix': fields.related('purchase_journal_id', 'sequence_id', 'prefix', type='char', string='Supplier invoice sequence'), 'purchase_sequence_next': fields.related('purchase_journal_id', 'sequence_id', 'number_next', type='integer', string='Next supplier invoice number'), 'purchase_refund_journal_id': fields.many2one('account.journal', 'Purchase refund journal'), 'purchase_refund_sequence_prefix': fields.related('purchase_refund_journal_id', 'sequence_id', 'prefix', type='char', string='Supplier credit note sequence'), 'purchase_refund_sequence_next': fields.related('purchase_refund_journal_id', 'sequence_id', 'number_next', type='integer', string='Next supplier credit note number'), 'module_account_check_writing': fields.boolean('Pay your suppliers by check', help='This allows you to check writing and printing.\n' '-This installs the module account_check_writing.'), 'module_account_accountant': fields.boolean('Full accounting features: journals, legal statements, chart of accounts, etc.', help="""If you do not check this box, you will be able to do invoicing & payments, but not accounting (Journal Items, Chart of Accounts, ...)"""), 'module_account_asset': fields.boolean('Assets management', help='This allows you to manage the assets owned by a company or a person.\n' 'It keeps track of the depreciation occurred on those assets, and creates account move for those depreciation lines.\n' '-This installs the module account_asset. If you do not check this box, you will be able to do invoicing & payments, ' 'but not accounting (Journal Items, Chart of Accounts, ...)'), 'module_account_budget': fields.boolean('Budget management', help='This allows accountants to manage analytic and crossovered budgets. ' 'Once the master budgets and the budgets are defined, ' 'the project managers can set the planned amount on each analytic account.\n' '-This installs the module account_budget.'), 'module_account_payment': fields.boolean('Manage payment orders', help='This allows you to create and manage your payment orders, with purposes to \n' '* serve as base for an easy plug-in of various automated payment mechanisms, and \n' '* provide a more efficient way to manage invoice payments.\n' '-This installs the module account_payment.' ), 'module_account_voucher': fields.boolean('Manage customer payments', help='This includes all the basic requirements of voucher entries for bank, cash, sales, purchase, expense, contra, etc.\n' '-This installs the module account_voucher.'), 'module_account_followup': fields.boolean('Manage customer payment follow-ups', help='This allows to automate letters for unpaid invoices, with multi-level recalls.\n' '-This installs the module account_followup.'), 'module_product_email_template': fields.boolean('Send products tools and information at the invoice confirmation', help='With this module, link your products to a template to send complete information and tools to your customer.\n' 'For instance when invoicing a training, the training agenda and materials will automatically be send to your customers.'), 'module_account_bank_statement_import_ofx': fields.boolean('Import of Bank Statements in .OFX Format', help='Get your bank statements from you bank and import them in Odoo in .OFX format.\n' '-that installs the module account_bank_statement_import.'), 'module_account_bank_statement_import_qif': fields.boolean('Import of Bank Statements in .QIF Format.', help='Get your bank statements from you bank and import them in Odoo in .QIF format.\n' '-that installs the module account_bank_statement_import_qif.'), 'group_proforma_invoices': fields.boolean('Allow pro-forma invoices', implied_group='account.group_proforma_invoices', help="Allows you to put invoices in pro-forma state."), 'default_sale_tax': fields.many2one('account.tax', 'Default sale tax', help="This sale tax will be assigned by default on new products."), 'default_purchase_tax': fields.many2one('account.tax', 'Default purchase tax', help="This purchase tax will be assigned by default on new products."), 'decimal_precision': fields.integer('Decimal precision on journal entries', help="""As an example, a decimal precision of 2 will allow journal entries like: 9.99 EUR, whereas a decimal precision of 4 will allow journal entries like: 0.0231 EUR."""), 'group_multi_currency': fields.boolean('Allow multi currencies', implied_group='base.group_multi_currency', help="Allows you multi currency environment"), 'group_analytic_accounting': fields.boolean('Analytic accounting', implied_group='analytic.group_analytic_accounting', help="Allows you to use the analytic accounting."), 'group_check_supplier_invoice_total': fields.boolean('Check the total of supplier invoices', implied_group="account.group_supplier_inv_check_total"), } def _default_company(self, cr, uid, context=None): user = self.pool.get('res.users').browse(cr, uid, uid, context=context) return user.company_id.id def _default_has_default_company(self, cr, uid, context=None): count = self.pool.get('res.company').search_count(cr, uid, [], context=context) return bool(count == 1) def _get_default_fiscalyear_data(self, cr, uid, company_id, context=None): """Compute default period, starting and ending date for fiscalyear - if in a fiscal year, use its period, starting and ending date - if past fiscal year, use its period, and new dates [ending date of the latest +1 day ; ending date of the latest +1 year] - if no fiscal year, use monthly, 1st jan, 31th dec of this year :return: (date_start, date_stop, period) at format DEFAULT_SERVER_DATETIME_FORMAT """ fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [('date_start', '<=', time.strftime(DF)), ('date_stop', '>=', time.strftime(DF)), ('company_id', '=', company_id)]) if fiscalyear_ids: # is in a current fiscal year, use this one fiscalyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_ids[0], context=context) if len(fiscalyear.period_ids) == 5: # 4 periods of 3 months + opening period period = '3months' else: period = 'month' return (fiscalyear.date_start, fiscalyear.date_stop, period) else: past_fiscalyear_ids = self.pool.get('account.fiscalyear').search(cr, uid, [('date_stop', '<=', time.strftime(DF)), ('company_id', '=', company_id)]) if past_fiscalyear_ids: # use the latest fiscal, sorted by (start_date, id) latest_year = self.pool.get('account.fiscalyear').browse(cr, uid, past_fiscalyear_ids[-1], context=context) latest_stop = datetime.datetime.strptime(latest_year.date_stop, DF) if len(latest_year.period_ids) == 5: period = '3months' else: period = 'month' return ((latest_stop+datetime.timedelta(days=1)).strftime(DF), latest_stop.replace(year=latest_stop.year+1).strftime(DF), period) else: return (time.strftime('%Y-01-01'), time.strftime('%Y-12-31'), 'month') _defaults = { 'company_id': _default_company, 'has_default_company': _default_has_default_company, } def create(self, cr, uid, values, context=None): id = super(account_config_settings, self).create(cr, uid, values, context) # Hack: to avoid some nasty bug, related fields are not written upon record creation. # Hence we write on those fields here. vals = {} for fname, field in self._columns.iteritems(): if isinstance(field, fields.related) and fname in values: vals[fname] = values[fname] self.write(cr, uid, [id], vals, context) return id def onchange_company_id(self, cr, uid, ids, company_id, context=None): # update related fields values = {} values['currency_id'] = False if company_id: company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) has_chart_of_accounts = company_id not in self.pool.get('account.installer').get_unconfigured_cmp(cr, uid) fiscalyear_count = self.pool.get('account.fiscalyear').search_count(cr, uid, [('date_start', '<=', time.strftime('%Y-%m-%d')), ('date_stop', '>=', time.strftime('%Y-%m-%d')), ('company_id', '=', company_id)]) date_start, date_stop, period = self._get_default_fiscalyear_data(cr, uid, company_id, context=context) values = { 'expects_chart_of_accounts': company.expects_chart_of_accounts, 'currency_id': company.currency_id.id, 'paypal_account': company.paypal_account, 'company_footer': company.rml_footer, 'has_chart_of_accounts': has_chart_of_accounts, 'has_fiscal_year': bool(fiscalyear_count), 'chart_template_id': False, 'tax_calculation_rounding_method': company.tax_calculation_rounding_method, 'date_start': date_start, 'date_stop': date_stop, 'period': period, } # update journals and sequences for journal_type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'): for suffix in ('_journal_id', '_sequence_prefix', '_sequence_next'): values[journal_type + suffix] = False journal_obj = self.pool.get('account.journal') journal_ids = journal_obj.search(cr, uid, [('company_id', '=', company_id)]) for journal in journal_obj.browse(cr, uid, journal_ids): if journal.type in ('sale', 'sale_refund', 'purchase', 'purchase_refund'): values.update({ journal.type + '_journal_id': journal.id, journal.type + '_sequence_prefix': journal.sequence_id.prefix, journal.type + '_sequence_next': journal.sequence_id.number_next, }) # update taxes ir_values = self.pool.get('ir.values') taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id) supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id) values.update({ 'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id, 'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id, }) return {'value': values} def onchange_chart_template_id(self, cr, uid, ids, chart_template_id, context=None): tax_templ_obj = self.pool.get('account.tax.template') res = {'value': { 'complete_tax_set': False, 'sale_tax': False, 'purchase_tax': False, 'sale_tax_rate': 15, 'purchase_tax_rate': 15, }} if chart_template_id: # update complete_tax_set, sale_tax and purchase_tax chart_template = self.pool.get('account.chart.template').browse(cr, uid, chart_template_id, context=context) res['value'].update({'complete_tax_set': chart_template.complete_tax_set}) if chart_template.complete_tax_set: # default tax is given by the lowest sequence. For same sequence we will take the latest created as it will be the case for tax created while isntalling the generic chart of account sale_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id", "=", chart_template_id), ('type_tax_use', 'in', ('sale','all'))], order="sequence, id desc") purchase_tax_ids = tax_templ_obj.search(cr, uid, [("chart_template_id", "=", chart_template_id), ('type_tax_use', 'in', ('purchase','all'))], order="sequence, id desc") res['value']['sale_tax'] = sale_tax_ids and sale_tax_ids[0] or False res['value']['purchase_tax'] = purchase_tax_ids and purchase_tax_ids[0] or False if chart_template.code_digits: res['value']['code_digits'] = chart_template.code_digits return res def onchange_tax_rate(self, cr, uid, ids, rate, context=None): return {'value': {'purchase_tax_rate': rate or False}} def onchange_multi_currency(self, cr, uid, ids, group_multi_currency, context=None): res = {} if not group_multi_currency: res['value'] = {'income_currency_exchange_account_id': False, 'expense_currency_exchange_account_id': False} return res def onchange_start_date(self, cr, uid, id, start_date): if start_date: start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d") end_date = (start_date + relativedelta(months=12)) - relativedelta(days=1) return {'value': {'date_stop': end_date.strftime('%Y-%m-%d')}} return {} def open_company_form(self, cr, uid, ids, context=None): config = self.browse(cr, uid, ids[0], context) return { 'type': 'ir.actions.act_window', 'name': 'Configure your Company', 'res_model': 'res.company', 'res_id': config.company_id.id, 'view_mode': 'form', } def set_default_taxes(self, cr, uid, ids, context=None): """ set default sale and purchase taxes for products """ if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'): raise openerp.exceptions.AccessError(_("Only administrators can change the settings")) ir_values = self.pool.get('ir.values') config = self.browse(cr, uid, ids[0], context) ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'taxes_id', config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id) ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'supplier_taxes_id', config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id) def set_chart_of_accounts(self, cr, uid, ids, context=None): """ install a chart of accounts for the given company (if required) """ config = self.browse(cr, uid, ids[0], context) if config.chart_template_id: assert config.expects_chart_of_accounts and not config.has_chart_of_accounts wizard = self.pool.get('wizard.multi.charts.accounts') wizard_id = wizard.create(cr, uid, { 'company_id': config.company_id.id, 'chart_template_id': config.chart_template_id.id, 'code_digits': config.code_digits or 6, 'sale_tax': config.sale_tax.id, 'purchase_tax': config.purchase_tax.id, 'sale_tax_rate': config.sale_tax_rate, 'purchase_tax_rate': config.purchase_tax_rate, 'complete_tax_set': config.complete_tax_set, 'currency_id': config.currency_id.id, }, context) wizard.execute(cr, uid, [wizard_id], context) def set_fiscalyear(self, cr, uid, ids, context=None): """ create a fiscal year for the given company (if necessary) """ config = self.browse(cr, uid, ids[0], context) if config.has_chart_of_accounts or config.chart_template_id: fiscalyear = self.pool.get('account.fiscalyear') fiscalyear_count = fiscalyear.search_count(cr, uid, [('date_start', '<=', config.date_start), ('date_stop', '>=', config.date_stop), ('company_id', '=', config.company_id.id)], context=context) if not fiscalyear_count: name = code = config.date_start[:4] if int(name) != int(config.date_stop[:4]): name = config.date_start[:4] +'-'+ config.date_stop[:4] code = config.date_start[2:4] +'-'+ config.date_stop[2:4] vals = { 'name': name, 'code': code, 'date_start': config.date_start, 'date_stop': config.date_stop, 'company_id': config.company_id.id, } fiscalyear_id = fiscalyear.create(cr, uid, vals, context=context) if config.period == 'month': fiscalyear.create_period(cr, uid, [fiscalyear_id]) elif config.period == '3months': fiscalyear.create_period3(cr, uid, [fiscalyear_id]) def get_default_dp(self, cr, uid, fields, context=None): dp = self.pool.get('ir.model.data').get_object(cr, uid, 'product','decimal_account') return {'decimal_precision': dp.digits} def set_default_dp(self, cr, uid, ids, context=None): config = self.browse(cr, uid, ids[0], context) dp = self.pool.get('ir.model.data').get_object(cr, uid, 'product','decimal_account') dp.write({'digits': config.decimal_precision}) def onchange_analytic_accounting(self, cr, uid, ids, analytic_accounting, context=None): if analytic_accounting: return {'value': { 'module_account_accountant': True, }} return {}
class sale_order_line(osv.osv): _inherit = "sale.order.line" def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context) if not pricelist: return res if context is None: context = {} frm_cur = self.pool.get('res.users').browse( cr, uid, uid).company_id.currency_id.id to_cur = self.pool.get('product.pricelist').browse( cr, uid, [pricelist])[0].currency_id.id if product: product = self.pool['product.product'].browse(cr, uid, product, context=context) #template = self.pool['product.template'].browse(cr, uid, template.product_tmpl_id=product, context=context) if product.variant_cost_price > 0: purchase_price = product.variant_cost_price else: purchase_price = product.standard_price to_uom = res.get('product_uom', uom) if to_uom != product.uom_id.id: purchase_price = self.pool['product.uom']._compute_price( cr, uid, product.uom_id.id, purchase_price, to_uom) ctx = context.copy() ctx['date'] = date_order price = self.pool.get('res.currency').compute(cr, uid, frm_cur, to_cur, purchase_price, round=False, context=ctx) price = purchase_price res['value'].update({'purchase_price': price}) return res def _product_margin(self, cr, uid, ids, field_name, arg, context=None): res = {} for line in self.browse(cr, uid, ids, context=context): res[line.id] = '' if line.product_id: res[line.id] = round( line.price_subtotal - ((line.purchase_price) * line.product_uos_qty), 2) return res _columns = { 'margin': fields.function(_product_margin, string='Margin', store=True), 'purchase_price': fields.float('Cost Price', digits=(16, 2)) }
class stock_move(osv.osv): _inherit = "stock.move" _columns = { 'move_returned_from': fields.many2one('stock.move', 'Move this move was returned from'), 'price_unit': fields.float('Unit Price', help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"), } def _check_company_location(self, cr, uid, ids, context=None): for record in self.browse(cr, uid, ids, context=context): if record.location_id.company_id and (record.company_id.id != record.location_id.company_id.id): raise osv.except_osv(_('Error'), _('The company of the source location (%s) and the company of the stock move (%s) should be the same') % (record.location_id.company_id.name, record.company_id.name)) if record.location_dest_id.company_id and (record.company_id.id != record.location_dest_id.company_id.id): raise osv.except_osv(_('Error'), _('The company of the destination location (%s) and the company of the stock move (%s) should be the same') % (record.location_dest_id.company_id.name, record.company_id.name)) return True _constraints = [ (_check_company_location, 'You cannot use a location from another company. ', ['company_id', 'location_id', 'location_dest_id'])] def _default_location_destination(self, cr, uid, context=None): """ Gets default address of partner for destination location @return: Address id or False """ mod_obj = self.pool.get('ir.model.data') picking_type = context.get('picking_type') location_id = False if context is None: context = {} if context.get('move_line', []): if context['move_line'][0]: if isinstance(context['move_line'][0], (tuple, list)): location_id = context['move_line'][0][2] and context['move_line'][0][2].get('location_dest_id',False) else: move_list = self.pool.get('stock.move').read(cr, uid, context['move_line'][0], ['location_dest_id']) location_id = move_list and move_list['location_dest_id'][0] or False elif context.get('address_out_id', False): property_out = self.pool.get('res.partner').browse(cr, uid, context['address_out_id'], context).property_stock_customer location_id = property_out and property_out.id or False else: location_xml_id = False if picking_type in ('in', 'internal'): location_xml_id = 'stock_location_stock' elif picking_type == 'out': location_xml_id = 'stock_location_customers' if location_xml_id: location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id) if location_id: location_company = self.pool.get("stock.location").browse(cr, uid, location_id, context=context).company_id user_company = self.pool.get("res.users").browse(cr, uid, uid, context=context).company_id.id if location_company and location_company.id != user_company: location_id = False return location_id def _default_location_source(self, cr, uid, context=None): """ Gets default address of partner for source location @return: Address id or False """ mod_obj = self.pool.get('ir.model.data') picking_type = context.get('picking_type') location_id = False if context is None: context = {} if context.get('move_line', []): try: location_id = context['move_line'][0][2]['location_id'] except: pass elif context.get('address_in_id', False): part_obj_add = self.pool.get('res.partner').browse(cr, uid, context['address_in_id'], context=context) if part_obj_add: location_id = part_obj_add.property_stock_supplier.id else: location_xml_id = False if picking_type == 'in': location_xml_id = 'stock_location_suppliers' elif picking_type in ('out', 'internal'): location_xml_id = 'stock_location_stock' if location_xml_id: location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id) if location_id: location_company = self.pool.get("stock.location").browse(cr, uid, location_id, context=context).company_id user_company = self.pool.get("res.users").browse(cr, uid, uid, context=context).company_id.id if location_company and location_company.id != user_company: location_id = False return location_id def onchange_move_type(self, cr, uid, ids, type, context=None): """ On change of move type gives sorce and destination location. @param type: Move Type @return: Dictionary of values """ mod_obj = self.pool.get('ir.model.data') location_source_id = 'stock_location_stock' location_dest_id = 'stock_location_stock' if type == 'in': location_source_id = 'stock_location_suppliers' location_dest_id = 'stock_location_stock' elif type == 'out': location_source_id = 'stock_location_stock' location_dest_id = 'stock_location_customers' source_location = mod_obj.get_object_reference(cr, uid, 'stock', location_source_id) dest_location = mod_obj.get_object_reference(cr, uid, 'stock', location_dest_id) #Check companies user_company = self.pool.get("res.users").browse(cr, uid, uid, context=context).company_id.id if source_location: location_company = self.pool.get("stock.location").browse(cr, uid, source_location[1], context=context).company_id if location_company and location_company.id != user_company: source_location = False if dest_location: location_company = self.pool.get("stock.location").browse(cr, uid, dest_location[1], context=context).company_id if location_company and location_company.id != user_company: dest_location = False return {'value':{'location_id': source_location and source_location[1] or False, 'location_dest_id': dest_location and dest_location[1] or False}} #We can use a preliminary type def get_reference_amount(self, cr, uid, move, qty, context=None): # if product is set to average price and a specific value was entered in the picking wizard, # we use it # by default the reference currency is that of the move's company reference_currency_id = move.company_id.currency_id.id #I use if move.product_id.cost_method != 'standard' and move.price_unit: reference_amount = move.product_qty * move.price_unit #Using move.price_qty instead of qty to have correct amount reference_currency_id = move.price_currency_id.id or reference_currency_id # Otherwise we default to the company's valuation price type, considering that the values of the # valuation field are expressed in the default currency of the move's company. else: if context is None: context = {} currency_ctx = dict(context, currency_id = move.company_id.currency_id.id) amount_unit = move.product_id.price_get('standard_price', context=currency_ctx)[move.product_id.id] reference_amount = amount_unit * qty return reference_amount, reference_currency_id def _get_reference_accounting_values_for_valuation(self, cr, uid, move, context=None): """ Return the reference amount and reference currency representing the inventory valuation for this move. These reference values should possibly be converted before being posted in Journals to adapt to the primary and secondary currencies of the relevant accounts. """ product_uom_obj = self.pool.get('product.uom') default_uom = move.product_id.uom_id.id qty = product_uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, default_uom) reference_amount, reference_currency_id = self.get_reference_amount(cr, uid, move, qty, context=context) return reference_amount, reference_currency_id def _create_product_valuation_moves(self, cr, uid, move, matches, context=None): """ Generate the appropriate accounting moves if the product being moved is subject to real_time valuation tracking, and the source or the destination location is internal (not both) This means an in or out move. Depending on the matches it will create the necessary moves """ ctx = context.copy() ctx['force_company'] = move.company_id.id valuation = self.pool.get("product.product").browse(cr, uid, move.product_id.id, context=ctx).valuation move_obj = self.pool.get('account.move') if valuation == 'real_time': if context is None: context = {} company_ctx = dict(context,force_company=move.company_id.id) journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation(cr, uid, move, context=company_ctx) reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, context=company_ctx) account_moves = [] # Outgoing moves (or cross-company output part) if move.location_id.company_id \ and (move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal'): #returning goods to supplier if move.location_dest_id.usage == 'supplier': account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, matches, acc_valuation, acc_src, reference_amount, reference_currency_id, 'out', context=company_ctx))] else: account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, matches, acc_valuation, acc_dest, reference_amount, reference_currency_id, 'out', context=company_ctx))] # Incoming moves (or cross-company input part) if move.location_dest_id.company_id \ and (move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal'): #goods return from customer if move.location_id.usage == 'customer': account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, matches, acc_dest, acc_valuation, reference_amount, reference_currency_id, 'in', context=company_ctx))] else: account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, matches, acc_src, acc_valuation, reference_amount, reference_currency_id, 'in', context=company_ctx))] if matches and move.product_id.cost_method in ('fifo', 'lifo'): outs = {} match_obj = self.pool.get("stock.move.matching") for match in match_obj.browse(cr, uid, matches, context=context): if match.move_out_id.id in outs: outs[match.move_out_id.id] += [match.id] else: outs[match.move_out_id.id] = [match.id] #When in stock was negative, you will get matches for the in also: account_moves_neg = [] for out_mov in self.browse(cr, uid, outs.keys(), context=context): journal_id_out, acc_src_out, acc_dest_out, acc_valuation_out = self._get_accounting_data_for_valuation(cr, uid, out_mov, context=company_ctx) reference_amount_out, reference_currency_id_out = self._get_reference_accounting_values_for_valuation(cr, uid, out_mov, context=company_ctx) if out_mov.location_dest_id.usage == 'supplier': # Is not the way it should be with acc_valuation account_moves_neg += [(journal_id_out, self._create_account_move_line(cr, uid, out_mov, outs[out_mov.id], acc_valuation_out, acc_src_out, reference_amount_out, reference_currency_id_out, 'out', context=company_ctx))] else: account_moves_neg += [(journal_id_out, self._create_account_move_line(cr, uid, out_mov, outs[out_mov.id], acc_valuation_out, acc_dest_out, reference_amount_out, reference_currency_id_out, 'out', context=company_ctx))] #Create account moves for outs which made stock go negative for j_id, move_lines in account_moves_neg: move_obj.create(cr, uid, {'journal_id': j_id, 'line_id': move_lines, 'ref': out_mov.picking_id and out_mov.picking_id.name, }) for j_id, move_lines in account_moves: move_obj.create(cr, uid, { 'journal_id': j_id, 'line_id': move_lines, 'ref': move.picking_id and move.picking_id.name}) def action_done(self, cr, uid, ids, context=None): """ Makes the move done and if all moves are done, it will finish the picking. @return: """ picking_ids = [] move_ids = [] wf_service = netsvc.LocalService("workflow") if context is None: context = {} todo = [] for move in self.browse(cr, uid, ids, context=context): if move.state=="draft": todo.append(move.id) if todo: self.action_confirm(cr, uid, todo, context=context) todo = [] #Do price calculation on moves matchresults = self.price_calculation(cr, uid, ids, context=context) for move in self.browse(cr, uid, ids, context=context): if move.state in ['done','cancel']: continue move_ids.append(move.id) if move.picking_id: picking_ids.append(move.picking_id.id) if move.move_dest_id.id and (move.state != 'done'): # Downstream move should only be triggered if this move is the last pending upstream move other_upstream_move_ids = self.search(cr, uid, [('id','!=',move.id),('state','not in',['done','cancel']), ('move_dest_id','=',move.move_dest_id.id)], context=context) if not other_upstream_move_ids: self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]}) if move.move_dest_id.state in ('waiting', 'confirmed'): self.force_assign(cr, uid, [move.move_dest_id.id], context=context) if move.move_dest_id.picking_id: wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr) if move.move_dest_id.auto_validate: self.action_done(cr, uid, [move.move_dest_id.id], context=context) self._create_product_valuation_moves(cr, uid, move, move.id in matchresults and matchresults[move.id] or [], context=context) if move.state not in ('confirmed','done','assigned'): todo.append(move.id) if todo: self.action_confirm(cr, uid, todo, context=context) self.write(cr, uid, move_ids, {'state': 'done', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context) for id in move_ids: wf_service.trg_trigger(uid, 'stock.move', id, cr) for pick_id in picking_ids: wf_service.trg_write(uid, 'stock.picking', pick_id, cr) return True def _create_account_move_line(self, cr, uid, move, matches, src_account_id, dest_account_id, reference_amount, reference_currency_id, type='', context=None): """ Generate the account.move.line values to post to track the stock valuation difference due to the processing of the given stock move. """ move_list = [] # Consists of access rights # TODO Check if amount_currency is not needed match_obj = self.pool.get("stock.move.matching") product_obj = self.pool.get('product.product') if move.product_id.supply_method =='produce' and type=='out' and move.product_id.cost_method in ['fifo', 'lifo']: if move.product_id.cost_method == 'fifo': order = 'date, id' else: order = 'date desc, id desc' matching_obj = self.pool.get('stock.mrp.matching') match_obj = self.pool.get('stock.move.matching') tuples = [] match_ids = matching_obj.search(cr, uid, [('product_id','=',move.product_id.id), ('mrp_qty','>',0),('move_out_id','=',False)], order=order) product_qty = move.product_qty move_list = {} for match in matching_obj.browse(cr, uid, match_ids): if product_qty <= 0: break if match.mrp_qty <= product_qty: matching_obj.write(cr, uid, match.id, {'mrp_qty': product_qty - match.mrp_qty}) if match.price_unit_mrp in move_list: move_list[match.price_unit_mrp] += product_qty else: move_list[match.price_unit_mrp] = product_qty tuples.append((match.move_in_id.id, product_qty, match.price_unit_mrp)) product_qty = product_qty - match.mrp_qty elif match.qty > product_qty: matching_obj.write(cr, uid, match.id, {'mrp_qty': match.mrp_qty - product_qty}) tuples.append((match.move_in_id.id, product_qty, match.price_unit_mrp)) product_qty = 0 if match.price_unit_mrp in move_list: move_list[match.price_unit_mrp] += match.mrp_qty else: move_list[match.price_unit_mrp] = match.mrp_qty if move_list: move_list = [ (qty, price * qty) for price, qty in move_list.items()] else: move_list = [(move.product_qty, move.product_qty * move.price_unit)] elif type == 'out' and move.product_id.cost_method in ['fifo', 'lifo']: for match in match_obj.browse(cr, uid, matches, context=context): move_list += [(match.qty, match.qty * match.price_unit_out)] elif move.production_id and type == 'in' and move.product_id.cost_method in ['fifo', 'lifo']: new_move_list, product_id, components, product_toconsume= {}, [], {}, {} if move.production_id.picking_id: for line in move.production_id.bom_id.bom_lines: product_toconsume.update({line.product_id.id: line.product_qty}) for component in move.production_id.picking_id.move_lines: out_ids = match_obj.search(cr, uid, [ ('move_out_id', '=', component.move_dest_id.id)],context=context) components[component.product_id.id] = [ [out.qty, out.price_unit] for out in match_obj.browse(cr, uid, out_ids) ] product_id.append(component.product_id.id) looplen = move.product_qty.is_integer() and int(move.product_qty) or int(move.product_qty+ 1) for loop in range(looplen): move_price = 0 for product, stock in components.items(): qty, price = product_toconsume[product], 0 for i in range(len(stock)): if qty == 0: break if stock[i][0] == 0: continue if stock[i][0] >= qty: price += qty * stock[i][1] stock[i][0] -= qty qty = 0 else: price += stock[i][1] * stock[i][0] qty -= stock[i][0] stock[i][0] = 0 move_price += price if move_price in new_move_list: new_move_list[move_price] += 1 else: new_move_list[move_price] = 1 move_list = [ (qty, price * qty) for price, qty in new_move_list.items()] new_price = 0 product_obj = self.pool.get('product.product') matching_obj = self.pool.get('stock.mrp.matching') for price, qty in new_move_list.items(): matchvals = {'move_in_id': move.id, 'price_unit_mrp': price, 'product_id': move.product_id.id, 'mrp_qty': qty} match_id = matching_obj.create(cr, uid, matchvals, context=context) new_price += price * qty product_obj.write(cr, uid, [move.product_id.id], {'standard_price': new_price / move.product_qty,}, context) self.write(cr, uid, move.id, {'price_unit': new_price / move.product_qty}, context=context) elif type == 'in' and move.product_id.cost_method in ['fifo', 'lifo']: move_list = [(move.product_qty, reference_amount)] else: move_list = [(move.product_qty, reference_amount)] res = [] for item in move_list: # prepare default values considering that the destination accounts have the reference_currency_id as their main currency partner_id = (move.picking_id.partner_id and self.pool.get('res.partner')._find_accounting_partner(move.picking_id.partner_id).id) or False debit_line_vals = { 'name': move.name, 'product_id': move.product_id and move.product_id.id or False, 'quantity': item[0], 'product_uom_id': move.product_uom.id, 'ref': move.picking_id and move.picking_id.name or False, 'date': time.strftime('%Y-%m-%d'), 'partner_id': partner_id, 'debit': item[1], 'account_id': dest_account_id, } credit_line_vals = { 'name': move.name, 'product_id': move.product_id and move.product_id.id or False, 'quantity': item[0], 'product_uom_id': move.product_uom.id, 'ref': move.picking_id and move.picking_id.name or False, 'date': time.strftime('%Y-%m-%d'), 'partner_id': partner_id, 'credit': item[1], 'account_id': src_account_id, } res += [(0, 0, debit_line_vals), (0, 0, credit_line_vals)] return res def _generate_negative_stock_matchings(self, cr, uid, ids, product, context=None): """ This method generates the stock move matches for out moves of product with qty remaining according to the in move force_company should be in context already | ids : id of in move | product: browse record of product Returns: | List of matches """ assert len(ids) == 1, _("Only generate negative stock matchings one by one") move = self.browse(cr, uid, ids, context=context)[0] cost_method = product.cost_method matching_obj = self.pool.get("stock.move.matching") product_obj = self.pool.get("product.product") uom_obj = self.pool.get("product.uom") res = [] #Search for the most recent out moves moves = self.search(cr, uid, [('company_id', '=', move.company_id.id), ('state','=', 'done'), ('location_id.usage','=','internal'), ('location_dest_id.usage', '!=', 'internal'), ('product_id', '=', move.product_id.id), ('qty_remaining', '>', 0.0)], order='date, id', context=context) qty_to_go = move.product_qty for out_mov in self.browse(cr, uid, moves, context=context): if qty_to_go <= 0.0: break out_qty_converted = uom_obj._compute_qty(cr, uid, out_mov.product_uom.id, out_mov.qty_remaining, move.product_uom.id, round=False) qty = 0.0 if out_qty_converted <= qty_to_go: qty = out_qty_converted elif qty_to_go > 0.0: qty = qty_to_go revert_qty = (qty / out_qty_converted) * out_mov.qty_remaining matchvals = {'move_in_id': move.id, 'qty': revert_qty, 'move_out_id': out_mov.id} match_id = matching_obj.create(cr, uid, matchvals, context=context) res.append(match_id) qty_to_go -= qty #Need to re-calculate total price of every out_move if FIFO/LIFO if cost_method in ['fifo', 'lifo']: matches = matching_obj.search(cr, uid, [('move_out_id', '=', out_mov.id)], context=context) amount = 0.0 total_price = 0.0 for match in matching_obj.browse(cr, uid, matches, context=context): amount += match.qty total_price += match.qty * match.price_unit_out if amount > 0.0: self.write(cr, uid, [out_mov.id], {'price_unit': total_price / amount}, context=context) if amount >= out_mov.product_qty: product_obj.write(cr, uid, [product.id], {'standard_price': total_price / amount}, context=context) return res def price_calculation(self, cr, uid, ids, context=None): ''' This method puts the right price on the stock move, adapts the price on the product when necessary and creates the necessary stock move matchings It returns a list of tuples with (move_id, match_id) which is used for generating the accounting entries when FIFO/LIFO ''' product_obj = self.pool.get('product.product') currency_obj = self.pool.get('res.currency') matching_obj = self.pool.get('stock.move.matching') uom_obj = self.pool.get('product.uom') product_avail = {} res = {} for move in self.browse(cr, uid, ids, context=context): # Initialize variables res[move.id] = [] move_qty = move.product_qty move_uom = move.product_uom.id company_id = move.company_id.id ctx = context.copy() user = self.pool.get('res.users').browse(cr, uid, uid, context=context) ctx['force_company'] = move.company_id.id product = product_obj.browse(cr, uid, move.product_id.id, context=ctx) cost_method = product.cost_method product_uom_qty = uom_obj._compute_qty(cr, uid, move_uom, move_qty, product.uom_id.id, round=False) if not product.id in product_avail: product_avail[product.id] = product.qty_available # Check if out -> do stock move matchings and if fifo/lifo -> update price # only update the cost price on the product form on stock moves of type == 'out' because if a valuation has to be made without PO, # for inventories for example we want to use the last value used for an outgoing move if move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal': fifo = (cost_method != 'lifo') tuples = product_obj.get_stock_matchings_fifolifo(cr, uid, [product.id], move_qty, fifo, move_uom, move.company_id.currency_id.id, context=ctx) #TODO Would be better to use price_currency_id for migration? price_amount = 0.0 amount = 0.0 #Write stock matchings for match in tuples: matchvals = {'move_in_id': match[0], 'qty': match[1], 'move_out_id': move.id} match_id = matching_obj.create(cr, uid, matchvals, context=context) res[move.id].append(match_id) price_amount += match[1] * match[2] amount += match[1] #Write price on out move if product_avail[product.id] >= product_uom_qty and product.cost_method in ['fifo', 'lifo']: if amount > 0: self.write(cr, uid, move.id, {'price_unit': price_amount / amount}, context=context) product_obj.write(cr, uid, product.id, {'standard_price': price_amount / product_uom_qty}, context=ctx) else: raise osv.except_osv(_('Error'), _("Something went wrong finding stock moves ") + str(tuples) + str(self.search(cr, uid, [('company_id','=', company_id), ('qty_remaining', '>', 0), ('state', '=', 'done'), ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal'), ('product_id', '=', product.id)], order = 'date, id', context=context)) + str(move_qty) + str(move_uom) + str(move.company_id.currency_id.id)) else: new_price = uom_obj._compute_price(cr, uid, product.uom_id.id, product.standard_price, move_uom) self.write(cr, uid, move.id, {'price_unit': new_price}, context=ctx) #Adjust product_avail when not average and move returned from if (not move.move_returned_from or product.cost_method != 'average'): product_avail[product.id] -= product_uom_qty #Check if in => if price 0.0, take standard price / Update price when average price and price on move != standard price if move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal': if move.price_unit == 0.0: new_price = uom_obj._compute_price(cr, uid, product.uom_id.id, product.standard_price, move_uom) self.write(cr, uid, move.id, {'price_unit': new_price}, context=ctx) elif product.cost_method == 'average': move_product_price = uom_obj._compute_price(cr, uid, move_uom, move.price_unit, product.uom_id.id) if product_avail[product.id] > 0.0: amount_unit = product.standard_price new_std_price = ((amount_unit * product_avail[product.id])\ + (move_product_price * product_uom_qty))/(product_avail[product.id] + product_uom_qty) else: new_std_price = move_product_price product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=ctx) # Should create the stock move matchings for previous outs for the negative stock that can be matched with is in if product_avail[product.id] < 0.0: resneg = self._generate_negative_stock_matchings(cr, uid, [move.id], product, context=ctx) res[move.id] += resneg product_avail[product.id] += product_uom_qty #The return of average products at average price (could be made optional) if move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal' and cost_method == 'average' and move.move_returned_from: move_orig = move.move_returned_from new_price = uom_obj._compute_price(cr, uid, move_orig.product_uom, move_orig.price_unit, product.uom_id.id) if (product_avail[product.id]- product_uom_qty) >= 0.0: amount_unit = product.standard_price new_std_price = ((amount_unit * product_avail[product.id])\ - (new_price * product_uom_qty))/(product_avail[product.id] - product_uom_qty) self.write(cr, uid, [move.id],{'price_unit': move_orig.price_unit,}) product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}, context=ctx) product_avail[product.id] -= product_uom_qty return res # FIXME: needs refactoring, this code is partially duplicated in stock_picking.do_partial()! def do_partial(self, cr, uid, ids, partial_datas, context=None): """ Makes partial pickings and moves done. @param partial_datas: Dictionary containing details of partial picking like partner_id, delivery_date, delivery moves with product_id, product_qty, uom """ res = {} picking_obj = self.pool.get('stock.picking') product_obj = self.pool.get('product.product') currency_obj = self.pool.get('res.currency') uom_obj = self.pool.get('product.uom') wf_service = netsvc.LocalService("workflow") if context is None: context = {} complete, too_many, too_few = [], [], [] move_product_qty, prodlot_ids, partial_qty, product_uoms = {}, {}, {}, {} for move in self.browse(cr, uid, ids, context=context): if move.state in ('done', 'cancel'): continue partial_data = partial_datas.get('move%s'%(move.id), {}) product_qty = partial_data.get('product_qty',0.0) move_product_qty[move.id] = product_qty product_uom = partial_data.get('product_uom',False) product_price = partial_data.get('product_price',0.0) product_currency = partial_data.get('product_currency',False) prodlot_id = partial_data.get('prodlot_id') prodlot_ids[move.id] = prodlot_id product_uoms[move.id] = product_uom partial_qty[move.id] = uom_obj._compute_qty(cr, uid, product_uoms[move.id], product_qty, move.product_uom.id) if move.product_qty == partial_qty[move.id]: complete.append(move) elif move.product_qty > partial_qty[move.id]: too_few.append(move) else: too_many.append(move) for move in too_few: product_qty = move_product_qty[move.id] if product_qty != 0: defaults = { 'product_qty' : product_qty, 'product_uos_qty': product_qty, 'picking_id' : move.picking_id.id, 'state': 'assigned', 'move_dest_id': False, 'price_unit': product_price, } prodlot_id = prodlot_ids[move.id] if prodlot_id: defaults.update(prodlot_id=prodlot_id) new_move = self.copy(cr, uid, move.id, defaults) complete.append(self.browse(cr, uid, new_move)) self.write(cr, uid, [move.id], { 'product_qty': move.product_qty - product_qty, 'product_uos_qty': move.product_qty - product_qty, 'prodlot_id': False, 'tracking_id': False, }) for move in too_many: self.write(cr, uid, [move.id], { 'product_qty': move.product_qty, 'product_uos_qty': move.product_qty, }) complete.append(move) for move in complete: if prodlot_ids.get(move.id): self.write(cr, uid, [move.id],{'prodlot_id': prodlot_ids.get(move.id)}) self.action_done(cr, uid, [move.id], context=context) if move.picking_id.id : # TOCHECK : Done picking if all moves are done cr.execute(""" SELECT move.id FROM stock_picking pick RIGHT JOIN stock_move move ON move.picking_id = pick.id AND move.state = %s WHERE pick.id = %s""", ('done', move.picking_id.id)) res = cr.fetchall() if len(res) == len(move.picking_id.move_lines): picking_obj.action_move(cr, uid, [move.picking_id.id]) wf_service.trg_validate(uid, 'stock.picking', move.picking_id.id, 'button_done', cr) return [move.id for move in complete]
class ids_employee_exit(osv.Model): _name = 'ids.employee.exit' _description = 'Employee Full & Final' _inherit = ['mail.thread', 'ir.needaction_mixin'] _columns = { 'fnf_number': fields.char('F&F Number', size=15, readonly=True), 'employee_id': fields.many2one( 'hr.employee', 'Employee Name', required=True, domain= "['|',('working_status', '=', 'resigned'),('working_status', '=', 'exit')]" ), 'job_id': fields.related('employee_id', 'job_id', type='many2one', relation='hr.job', string='Job Position', store=True, readonly=True), 'department_id': fields.related('employee_id', 'department_id', type='many2one', relation='hr.department', string='Department', store=True, readonly=True), 'joining_date': fields.related('employee_id', 'joining_date', type='date', relation='hr.employee', string='Joining Date', store=True, readonly=True), 'confirmation_status': fields.related('employee_id', 'confirmation_status', type='char', relation='hr.employee', string='Employee status', store=True, readonly=True), 'resign_id': fields.many2one('ids.hr.employee.separation', 'Resign ID'), 'nodues_id': fields.many2one('emp.no.dues', 'No Dues ID'), 'capture_date': fields.related('resign_id', 'capture_date', type='date', relation='ids.hr.employee.separation', string='Resignation Date ', store=True), 'last_date': fields.related('resign_id', 'last_date', type='date', relation='ids.hr.employee.separation', string='Last Working Day', store=True), 'dob': fields.related('employee_id', 'birthday', type='char', relation='hr.employee', string='Date Of Birth', store=True, readonly=True), 'division_id': fields.related('employee_id', 'division', type='many2one', relation='division', string='Division', store=True, readonly=True), 'location_id': fields.related('employee_id', 'office_location', type='many2one', relation='office.location', string='Location', store=True, readonly=True), 'gender': fields.related('employee_id', 'gender', type='char', relation='hr.employee', string='Gender', store=True, readonly=True), 'mobile_no': fields.related('employee_id', 'mobile_phone', type='char', relation='hr.employee', string='Mobile No', store=True, readonly=True), 'state': fields.selection([('draft', 'Draft'), ('phase1', 'Phase-1'), ('phase2', 'Phase-2'), ('phase3', 'Phase-3'), ('completed', 'Completed')], 'Status', readonly=True), #Leave Details Columns 'leave_detail_ids': fields.one2many('ids.employee.ff.leave', 'fullfinal_id', 'Leave Details', readonly=True, store=True, ondelete="cascade"), #Notice Period Details Columns 'np_required': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Notice Period Required', required=True), 'reason_no': fields.text('Reason For No'), 'shortfall': fields.float('Shortfall in Notice Period(Days)'), 'shortfall_reason': fields.text('Reasons for shortfall'), #Gratuity Details Columns 'last_wages': fields.float('Amount of wages last claimed'), 'service_period': fields.char('Total period of service'), 'eligibility': fields.selection([('yes', 'Yes'), ('no', 'No')], 'Eligibility', required=True), 'gratuity_years': fields.integer('Gratuity Years'), 'amount_claimed': fields.float('Amount of gratuity claimed'), #Agreement Details Columns 'service_agreement': fields.selection([('yes', 'Yes'), ('no', 'No')], 'Service Agreement', required=True), 'start_date': fields.date('Start Date'), 'end_date': fields.date('End Date'), 'recoverable_applicable': fields.selection([('yes', 'Yes'), ('no', 'No')], 'Recoverable Applicable', required=True), 'amount': fields.float('Amount'), 'valid_date': fields.date('Valid Date'), #Attendance Details Columns 'last_month_days': fields.float('25th to 30th/31th of previous month(Days)'), 'cur_month_days': fields.float('1st till last working day(Days)'), #Bonus Information Columns 'bonus': fields.selection([('yes', 'Yes'), ('no', 'No')], 'Bonus', required=True), 'bonus_amount': fields.float('Amount'), 'lta': fields.selection([('yes', 'Yes'), ('no', 'No')], 'LTA', required=True), 'lta_amount': fields.float('Amount'), 'loyalty': fields.selection([('yes', 'Yes'), ('no', 'No')], 'Loyalty', required=True), 'loyalty_amount': fields.float('Amount'), #Allowance Details Columns 'night_allow': fields.float('Night Allowance'), 'night_month': fields.selection([('1', 'January'), ('2', 'February'), ('3', 'March'), ('4', 'April'), ('5', 'May'), ('6', 'June'), ('7', 'July'), ('8', 'August'), ('9', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], 'Month'), 'ot_allow': fields.float('Overtime Allowance'), 'ot_month': fields.selection([('1', 'January'), ('2', 'February'), ('3', 'March'), ('4', 'April'), ('5', 'May'), ('6', 'June'), ('7', 'July'), ('8', 'August'), ('9', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], 'Month'), 'attendance_allow': fields.float('Attendance Allowance'), 'attendance_month': fields.selection([('1', 'January'), ('2', 'February'), ('3', 'March'), ('4', 'April'), ('5', 'May'), ('6', 'June'), ('7', 'July'), ('8', 'August'), ('9', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], 'Month'), 'prod_incentive': fields.float('Production Incentive'), 'incentive_month': fields.selection([('1', 'January'), ('2', 'February'), ('3', 'March'), ('4', 'April'), ('5', 'May'), ('6', 'June'), ('7', 'July'), ('8', 'August'), ('9', 'September'), ('10', 'October'), ('11', 'November'), ('12', 'December')], 'Month'), #No Dues Details Columns(Facility) 'icard_return': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'I-Card Return', required=True), 'access_card_return': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Access Card Return', required=True), 'keys_return': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Keys Return', required=True), 'headphone_return': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Head Phone Return', required=True), 'name_delete': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Name delete from attendance Registers', required=True), 'canteen_dues': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Canteen dues Cleared', required=True), 'library_book': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Library Books Return', required=True), 'remarks': fields.char('Remarks'), 'submitted_by_facility': fields.many2one('res.users', 'Submitted By'), 'submitted_on_facility': fields.datetime('Submitted On'), #No Dues Details Columns(Operation) 'email_control': fields.char('Email Control'), 'email_remarks': fields.char('Remarks'), 'internet_control': fields.char('Internet Control'), 'internet_remarks': fields.char('Remarks'), 'remote_control': fields.char('Remote Control'), 'remote_remarks': fields.char('Remarks'), 'software_requirement': fields.char('Software Requirement'), 'software_remarks': fields.char('Remarks'), 'application_share': fields.char('Application Share Access'), 'application_remarks': fields.char('Remarks'), 'data_backup': fields.char('Databack-up Details'), 'data_backup_remarks': fields.char('Remarks'), 'handover_takeover': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Handover Takeover Done', required=True), 'handover_remarks': fields.char('Remarks(if any items not return)'), 'submitted_by_operation': fields.many2one('res.users', 'Submitted By'), 'submitted_on_operation': fields.datetime('Submitted On'), #No Dues Details Columns(Technical) 'login_name_tech': fields.char('Login Name'), 'login_name_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'login_remarks_tech': fields.char('User-Name Remarks'), 'allocation_it_asset': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Allocation of IT Assets'), 'it_assets_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'asset_remarks_tech': fields.char('Asset Remarks'), 'email_id_tech': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Email ID Created'), 'email_id_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'email_remarks_tech': fields.char('Email Remarks'), 'internet_control_tech': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Internet Access Control'), 'internal_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'internet_remarks_tech': fields.char('Internet Remarks'), 'backup_setup_tech': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Back-Up Setup'), 'backup_setup_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'backup_remarks_tech': fields.char('Back-up Remarks'), 'software_requirement_tech': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Software Provisioning and Access Control'), 'software_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'software_remarks_tech': fields.char('Software Provisioning Remarks'), 'application_share_tech': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Application Share Access'), 'appliaction_share_disable': fields.selection([('yes', 'Yes'), ('no', 'No'), ('na', 'N/A')], 'Disable'), 'application_remarks_tech': fields.char('Share Access Remarks'), 'submitted_by_technical': fields.many2one('res.users', 'Submitted By'), 'submitted_on_technical': fields.datetime('Submitted On'), # Remarks Column 'group_hr_remarks': fields.text('Group HR Remarks'), 'group_head_remarks': fields.text('Group Head Remarks'), 'corp_hr_remarks': fields.text('Corp HR Remarks'), 'hr_head_remarks': fields.text('HR Head Remarks'), 'image_sign': fields.binary( "Sign", help= "This field holds the image used as sign, limited to 1024x1024px." ), } _rec_name = 'fnf_number' _defaults = { 'state': 'draft', 'capture_date': fields.date.context_today, } def create(self, cr, uid, vals, context=None): """Create the unique id """ vals['fnf_number'] = self.pool.get('ir.sequence').get( cr, uid, 'ids.employee.exit') res = super(ids_employee_exit, self).create(cr, uid, vals) return res def unlink(self, cr, uid, ids, context=None): for rec in self.browse(cr, uid, ids, context=context): if rec.state not in ['draft']: raise osv.except_osv( _('Warning!'), _('You cannot delete a full and final entry which is not in draft state.' )) return super(ids_employee_exit, self).unlink(cr, uid, ids, context) def submit_draft(self, cr, uid, ids, context=None): """Draft Submit. """ return self.write(cr, uid, ids, {'state': 'phase1'}) def submit_phase1(self, cr, uid, ids, context=None): """PHASE-1 Submit. """ return self.write(cr, uid, ids, {'state': 'phase2'}) def cancel_phase1(self, cr, uid, ids, context=None): """PHASE-1 Cancel. """ return self.write(cr, uid, ids, {'state': 'draft'}) def submit_phase2(self, cr, uid, ids, context=None): """PHASE-2 Submit. """ return self.write(cr, uid, ids, {'state': 'phase3'}) def submit_phase3(self, cr, uid, ids, context=None): """PHASE-3 Submit. """ return self.write(cr, uid, ids, {'state': 'completed'}) def cancel_phase3(self, cr, uid, ids, context=None): """PHASE-3 Cancel. """ return self.write(cr, uid, ids, {'state': 'phase2'}) def _calculate_years_between_two_dates(self, cr, uid, ids, start_date, end_date, context=None): d1 = datetime.strptime(start_date, DEFAULT_SERVER_DATE_FORMAT).date() d2 = datetime.strptime(end_date, DEFAULT_SERVER_DATE_FORMAT).date() r = relativedelta(d2, d1) year = str(r.years) month = str(r.months) day = str(r.days) service_period = year + ' years,' + month + ' month,' + day + ' days' gt_years = r.years if r.months > 5: gt_years = r.years + 1 return service_period, gt_years def onchange_last_wages(self, cr, uid, ids, last_wages, eligibility, gratuity_years, context=None): res = {'value': {'amount_claimed': False}} if eligibility == 'yes': res['value']['amount_claimed'] = (gratuity_years * last_wages * 15) / 26 else: res['value']['amount_claimed'] = 0 return res def calculate_shortfall(self, cr, uid, ids, employee_id, np_required, capture_date, last_date, context=None): shortfall = 0 if np_required == 'yes': notice_period_days = 0 if employee_id: employee = self.pool.get('hr.employee').browse( cr, uid, employee_id) notice_period_days = int(employee.notice) last = datetime.strptime( capture_date, "%Y-%m-%d") + timedelta(days=notice_period_days) shortfall = (last - datetime.strptime(last_date, "%Y-%m-%d")).days return {'value': {'shortfall': shortfall}} def onchange_employee(self, cr, uid, ids, employee_id, context=None): res = { 'value': { 'job_id': False, 'department_id': False, 'joining_date': False, 'confirmation_status': False, 'resign_id': False, 'capture_date': False, 'last_date': False, 'nodues_id': False, } } joining_date = '' last_date = '' if employee_id: exit_ids = self.search(cr, uid, [('employee_id', '=', employee_id)], context=context) if len(exit_ids) > 0: raise osv.except_osv( _('Warning!'), _('Full & Final has already been in progress/done for this employee.' )) ee = self.pool.get('hr.employee').browse(cr, uid, employee_id, context=context) if ee: notice_period_days = int(ee.notice) if notice_period_days > 0: res['value']['np_required'] = 'yes' res['value']['job_id'] = ee.job_id.id res['value']['department_id'] = ee.department_id.id res['value']['dob'] = ee.birthday res['value']['division_id'] = ee.division.id res['value']['location_id'] = ee.office_location.id res['value']['gender'] = ee.gender res['value']['mobile_no'] = ee.mobile_phone joining_date = res['value']['joining_date'] = ee.joining_date res['value'][ 'confirmation_status'] = ee.confirmation_status.title() emp_ff_leave_obj = self.pool.get('ids.employee.ff.leave') leave_ids = emp_ff_leave_obj._get_leave_details(cr, uid, ids, employee_id, context=None) res['value']['leave_detail_ids'] = leave_ids if ee.service_agreement == True: res['value']['service_agreement'] = 'yes' res['value']['start_date'] = ee.agreement_start_date res['value']['end_date'] = ee.agreement_end_date else: res['value']['service_agreement'] = 'no' emp_sep_id = self.pool.get('ids.hr.employee.separation').search( cr, uid, [('employee_id', '=', employee_id), ('state', '=', 'done')], context=context) if emp_sep_id: es = self.pool.get('ids.hr.employee.separation').browse( cr, uid, emp_sep_id[0], context=context) if es: res['value']['resign_id'] = es.id res['value']['capture_date'] = es.capture_date last_date = res['value']['last_date'] = es.last_date emp_contract = self.pool.get('hr.contract').search( cr, uid, [('employee_id', '=', employee_id)], context=context) if emp_contract: ec = self.pool.get('hr.contract').browse(cr, uid, emp_contract[0], context=context) if ec: res['value']['last_wages'] = ec.basic emp_nodues_id = self.pool.get('emp.no.dues').search( cr, uid, [('employee_id', '=', employee_id)], context=context) if emp_nodues_id: en = self.pool.get('emp.no.dues').browse(cr, uid, emp_nodues_id[0], context=context) if en: res['value']['nodues_id'] = en.id res['value']['icard_return'] = en.icard_return res['value']['access_card_return'] = en.access_card_return res['value']['keys_return'] = en.keys_return res['value']['headphone_return'] = en.headphone_return res['value']['name_delete'] = en.name_delete res['value']['canteen_dues'] = en.canteen_dues res['value']['library_book'] = en.library_book res['value']['remarks'] = en.remarks res['value'][ 'submitted_by_facility'] = en.submitted_by_facility res['value'][ 'submitted_on_facility'] = en.submitted_on_facility res['value']['email_control'] = en.email_control res['value']['email_remarks'] = en.email_remarks res['value']['internet_control'] = en.internet_control res['value']['internet_remarks'] = en.internet_remarks res['value']['remote_control'] = en.remote_control res['value']['remote_remarks'] = en.remote_remarks res['value'][ 'software_requirement'] = en.software_requirement res['value']['software_remarks'] = en.software_remarks res['value']['application_share'] = en.application_share res['value'][ 'application_remarks'] = en.application_remarks res['value']['data_backup'] = en.data_backup res['value'][ 'data_backup_remarks'] = en.data_backup_remarks res['value']['handover_takeover'] = en.handover_takeover res['value']['handover_remarks'] = en.handover_remarks res['value'][ 'submitted_by_operation'] = en.submitted_by_operation res['value'][ 'submitted_on_operation'] = en.submitted_on_operation res['value']['login_name_tech'] = en.login_name_tech res['value']['login_name_disable'] = en.login_name_disable res['value']['login_remarks_tech'] = en.login_remarks_tech res['value'][ 'allocation_it_asset'] = en.allocation_it_asset res['value']['it_assets_disable'] = en.it_assets_disable res['value']['asset_remarks_tech'] = en.asset_remarks_tech res['value']['email_id_tech'] = en.email_id_tech res['value']['email_id_disable'] = en.email_id_disable res['value']['email_remarks_tech'] = en.email_remarks_tech res['value'][ 'internet_control_tech'] = en.internet_control_tech res['value']['internal_disable'] = en.internal_disable res['value'][ 'internet_remarks_tech'] = en.internet_remarks_tech res['value']['backup_setup_tech'] = en.backup_setup_tech res['value'][ 'backup_setup_disable'] = en.backup_setup_disable res['value'][ 'backup_remarks_tech'] = en.backup_remarks_tech res['value'][ 'software_requirement_tech'] = en.software_requirement_tech res['value']['software_disable'] = en.software_disable res['value'][ 'software_remarks_tech'] = en.software_remarks_tech res['value'][ 'application_share_tech'] = en.application_share_tech res['value'][ 'appliaction_share_disable'] = en.appliaction_share_disable res['value'][ 'application_remarks_tech'] = en.application_remarks_tech res['value'][ 'submitted_by_technical'] = en.submitted_by_technical res['value'][ 'submitted_on_technical'] = en.submitted_on_technical if (joining_date and last_date): res['value'][ 'gratuity_years'] = self._calculate_years_between_two_dates( cr, uid, ids, joining_date, last_date, context=None)[1] res['value'][ 'service_period'] = self._calculate_years_between_two_dates( cr, uid, ids, joining_date, last_date, context=None)[0] return res
# asset_lines_obj.write(cr, uid, asset_line.get('id'), {'move_check': True, 'move_id': created_id}) # logging.getLogger(self._name).info("""account.move.line created for {0}""".format(asset_name)) # except: # logging.getLogger('account.asset.asset').error( # """ERROR creating the entries of # account move from {0}.""".format(__name__)) # raise orm.except_orm('Error', 'Failure creating the' # ' account move lines.') # # #else: # # logging.getLogger(self._name).info("Este activo ya esta asentado!") _columns = { 'department_id' : fields.many2one('hr.department', 'Departament'), 'life_expectancy' : fields.float('Life Expectancy', help="""Life expectancy of the asset in years."""), 'life_expectancy_percentage': fields.float('Life Expectancy Percentage'), 'stage_id': fields.many2one('account.asset.stage', 'Stage', help="""The stage of the asset indicate in wich point of his life is at the moment. You can add new stages in configuration."""), 'code': fields.char("Code", size=9, required=True), 'model_id': fields.many2one('account.asset.model', 'Model'), 'brand_id': fields.related('model_id', 'brand_id', string='Brand', type="many2one", relation="account.asset.model", readonly=True), 'category': fields.selection(( ('administrative', 'Administrative'), ('scholarly', 'Scholarly'), ('none', 'None')), 'Type of asset', help="""The type of asset, scholarly or administrative."""), 'asset_move_ids': fields.one2many('account.asset.move', 'asset_id', 'Movements')
class crm_opportunity_report(osv.Model): """ CRM Opportunity Analysis """ _name = "crm.opportunity.report" _auto = False _description = "CRM Opportunity Analysis" _rec_name = 'date_deadline' _columns = { 'date_deadline': fields.date('Expected Closing', readonly=True), 'create_date': fields.datetime('Creation Date', readonly=True), 'opening_date': fields.datetime('Assignation Date', readonly=True), 'date_closed': fields.datetime('Close Date', readonly=True), 'date_last_stage_update': fields.datetime('Last Stage Update', readonly=True), 'active': fields.boolean('Active', readonly=True), # durations 'delay_open': fields.float('Delay to Assign', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to open the case"), 'delay_close': fields.float('Delay to Close', digits=(16, 2), readonly=True, group_operator="avg", help="Number of Days to close the case"), 'delay_expected': fields.float('Overpassed Deadline', digits=(16, 2), readonly=True, group_operator="avg"), 'user_id': fields.many2one('res.users', 'User', readonly=True), 'team_id': fields.many2one('crm.team', 'Sales Team', oldname='section_id', readonly=True), 'nbr_activities': fields.integer('# of Activities', readonly=True), 'city': fields.char('City'), 'country_id': fields.many2one('res.country', 'Country', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'probability': fields.float('Probability', digits=(16, 2), readonly=True, group_operator="avg"), 'total_revenue': fields.float('Total Revenue', digits=(16, 2), readonly=True), 'expected_revenue': fields.float('Expected Revenue', digits=(16, 2), readonly=True), 'stage_id': fields.many2one( 'crm.stage', 'Stage', readonly=True, domain="['|', ('team_id', '=', False), ('team_id', '=', team_id)]" ), 'stage_name': fields.char('Stage Name', readonly=True), 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'priority': fields.selection(crm_stage.AVAILABLE_PRIORITIES, 'Priority'), 'type': fields.selection( [ ('lead', 'Lead'), ('opportunity', 'Opportunity'), ], 'Type', help="Type is used to separate Leads and Opportunities"), 'lost_reason': fields.many2one('crm.lost.reason', 'Lost Reason', readonly=True), 'date_conversion': fields.datetime('Conversion Date', readonly=True), 'campaign_id': fields.many2one('utm.campaign', 'Campaign', readonly=True), 'source_id': fields.many2one('utm.source', 'Source', readonly=True), 'medium_id': fields.many2one('utm.medium', 'Medium', readonly=True), } def init(self, cr): tools.drop_view_if_exists(cr, 'crm_opportunity_report') cr.execute(""" CREATE OR REPLACE VIEW crm_opportunity_report AS ( SELECT c.id, c.date_deadline, c.date_open as opening_date, c.date_closed as date_closed, c.date_last_stage_update as date_last_stage_update, c.user_id, c.probability, c.stage_id, stage.name as stage_name, c.type, c.company_id, c.priority, c.team_id, (SELECT COUNT(*) FROM mail_message m WHERE m.model = 'crm.lead' and m.res_id = c.id) as nbr_activity, c.active, c.campaign_id, c.source_id, c.medium_id, c.partner_id, c.city, c.country_id, c.planned_revenue as total_revenue, c.planned_revenue*(c.probability/100) as expected_revenue, c.create_date as create_date, extract('epoch' from (c.date_closed-c.create_date))/(3600*24) as delay_close, abs(extract('epoch' from (c.date_deadline - c.date_closed))/(3600*24)) as delay_expected, extract('epoch' from (c.date_open-c.create_date))/(3600*24) as delay_open, c.lost_reason, c.date_conversion as date_conversion FROM "crm_lead" c LEFT JOIN "crm_stage" stage ON stage.id = c.stage_id GROUP BY c.id, stage.name )""")
_columns = { 'checklist_task_id': fields.many2one('checklist.task', 'Checklist Task', required=True, ondelete='cascade'), 'checklist_id': fields.related('checklist_task_id', 'checklist_id', type='many2one', relation='checklist', string='Checklist'), 'model_id': fields.related('checklist_id', 'model_id', type='many2one', relation='ir.model', string='Model'), 'name': fields.related('checklist_task_id', 'name', type='char', size=128, string='Name'), 'mandatory': fields.related('checklist_task_id', 'mandatory', type='boolean', string='Mandatory', help='Required to make active object'), 'res_id': fields.integer('Resource ID', select=True, required=True), 'active': fields.function(_get_activity, type='boolean', string='Active', store=False, multi='activity'), 'sequence': fields.function(_get_activity, type='integer', string='Priority', store={ 'checklist.task': (_get_checklist_task_instance_ids, ['sequence'], 10), }, multi='activity'), 'field_ids_to_fill': fields.function(_get_activity, type='one2many', relation='checklist.task.field', string='Fields to fill', store=False, multi='activity'), 'field_ids_filled': fields.function(_get_activity, type='one2many', relation='checklist.task.field', string='Filled fields', store=False, multi='activity'), 'progress_rate': fields.float('Progress Rate', digits=(16, 2)), } _defaults = { 'progress_rate': 0.0, 'sequence': 15, } class ChecklistException(osv.osv): _name = 'checklist.exception' _description = 'Checklist Exception' _rec_name = 'checklist_task_id' _order = "create_date desc" def ChecklistExceptionEmail(self, cr, uid, company_id, method, checklist_task_id, object_id, action_id, exception, stack):
class product_scale_system_product_line(Model): _name = 'product.scale.system.product.line' _order = 'scale_system_id, sequence' _TYPE_SELECTION = [ ('id', 'Product ID'), ('numeric', 'Numeric Field'), ('text', 'Char / Text Field'), ('external_text', 'External Text Field'), ('constant', 'Constant Value'), ('external_constant', 'External Constant Text Value'), ('many2one', 'ManyOne Field'), ('many2many', 'Many2Many Field'), ('product_image', 'Product Image'), ] # Column Section _columns = { 'scale_system_id': fields.many2one( 'product.scale.system', 'Scale System', required=True, ondelete='cascade', select=True), 'company_id': fields.related( 'scale_system_id', 'company_id', type='many2one', string='Company', relation='res.company', store=True), 'code': fields.char(string='Bizerba Code', required=True), 'name': fields.char(string='Name', required=True), 'sequence': fields.integer(string='Sequence', required=True), 'type': fields.selection( _TYPE_SELECTION, string='Type'), 'field_id': fields.many2one( 'ir.model.fields', string='Product Field', domain="[" "('model', 'in', ['product.product', 'product.template'])]"), # TODO Improve. Set domain, depending on the other field 'related_field_id': fields.many2one( 'ir.model.fields', string='M2M / M2O Field', help="Used only" " for the x2x fields. Set here the field of the related model" " that you want to send to the scale. Let empty to send the ID."), 'x2many_range': fields.integer( string='range of the x2Many Fields', help="Used if type is" " 'Many2Many Field', to mention the" " range of the field to send. Begin by 0. (used for exemple" " for product logos)"), 'constant_value': fields.char( string='Constant Value', help="Used if type is 'constant'," " to send allways the same value."), 'multiline_length': fields.integer( string='Length for Multiline', help="Used if type is 'Text Field' or 'External Text Constant'" ", to indicate the max length of a line. Set 0 to avoid to split" " the value."), 'multiline_separator': fields.char( string='Separator for Multiline', help="Used if type is" " 'Text Field' or 'External Text Constant', to indicate wich text" " will be used to mention break lines."), # TODO Improve. Set contrains. 'suffix': fields.char( string='Suffix', help="Used if type is" " 'External Text Field', to indicate how to suffix the field.\n" " Make sure to have a uniq value by Scale System, and all with the" " same size.\n\n Used if type is Product Image to mention the end" " of the file. Exemple : '_01.jpg'."), 'numeric_coefficient': fields.float( string='Numeric Coefficient', help="Used if type is" " 'Numeric Field', to mention with coefficient numeric" " field should be multiplyed."), 'numeric_round': fields.float( string='Rounding Method', help="Used if type is" " 'Numeric Field', to mention how the value should be rounded.\n" " Do not Use 0, because it will truncate the value."), 'delimiter': fields.char( string='Delimiter Char', help="Used to finish the column"), } _defaults = { 'sequence': 10, 'multiline_length': 0, 'multiline_separator': '\n', 'numeric_coefficient': 1, 'numeric_round': 1, 'delimiter': '#', }
import time from openerp.osv import orm, fields from openerp.addons import decimal_precision as dp from .res_company import COMPANY_FISCAL_TYPE, COMPANY_FISCAL_TYPE_DEFAULT FISCAL_RULE_COLUMNS = { 'partner_fiscal_type_id': fields.many2one( 'l10n_br_account.partner.fiscal.type', 'Tipo Fiscal do Parceiro'), 'fiscal_category_id': fields.many2one( 'l10n_br_account.fiscal.category', 'Categoria'), 'fiscal_type': fields.selection(COMPANY_FISCAL_TYPE, u'Regime Tributário', required=True), 'revenue_start': fields.float( 'Faturamento Inicial', digits_compute=dp.get_precision('Account'), help="Faixa inicial de faturamento bruto"), 'revenue_end': fields.float( 'Faturamento Final', digits_compute=dp.get_precision('Account'), help="Faixa inicial de faturamento bruto") } OTHERS_FISCAL_RULE_COLUMNS_TEMPLATE = { 'parent_id': fields.many2one( 'account.fiscal.position.rule.template', 'Regra Pai'), 'child_ids': fields.one2many( 'account.fiscal.position.rule.template', 'parent_id', 'Regras Filhas'), } OTHERS_FISCAL_RULE_COLUMNS = {
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): result = super(product_search_ept, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu) if context is None: context={} self._columns = {} self._columns['product_ids'] = fields.text('Product IDS') if view_type != 'form': return result _moves_arch_lst = """ <form string="Stone Search" version="7.0"> <div> """ #_moves_arch_lst += """<group colspan="4" col="10">""" _line_fields = result['fields'] info = [ {'model':None,'_column_name':'product_name','label':'Stone ID','type':'char','name':'name','product_search_type':'char'}, {'model':None,'_column_name':'product_certificate_no','label':'Certificate No.','type':'char','name':'certificate_no','product_search_type':'char'}, {'model':None,'_column_name':'product_weight','label':'Weight','no':3,'type':'float','name':'weight','product_search_type':'char','range':True}, {'model':None,'_column_name':'product_price_caret','label':'PPC','no':1,'type':'float','name':'price_caret','product_search_type':'char','range':True}, {'model':None,'_column_name':'product_discount','label':'Back%','no':1,'type':'float','name':'discount','product_search_type':'char','range':True}, {'model':'product.shape','width':'15%','_column_name':'product_shape','label':'SHP','help':'Shape','type':'many2one','name':'shape_id','product_search_type':'boolean','on_change':'product_shape_change'}, {'model':'product.color','width':'8%','_column_name':'product_color','label':'CLR','help':'Color','type':'many2one','name':'color_id','product_search_type':'boolean','on_change':'product_color_change'}, {'model':'product.clarity','width':'10%','_column_name':'product_clarity','label':'CLRTY','help':'Clarity','type':'many2one','name':'clarity_id','product_search_type':'boolean','on_change':'product_clarity_change'}, {'model':'product.cut','width':'12%','_column_name':'product_cut','label':'CUT','help':'Cut','type':'many2one','name':'cut_id','product_search_type':'boolean','on_change':'product_cut_change'}, {'model':'product.polish','width':'8%','_column_name':'product_polish','label':'POL','help':'Polish','type':'many2one','name':'polish_id','product_search_type':'boolean','on_change':'product_polish_change'}, {'model':'product.symmetry','width':'10%','_column_name':'product_symmetry','label':'SYM','help':'Symmetry','type':'many2one','name':'symmetry_id','product_search_type':'boolean','on_change':'product_symmetry_change'}, {'model':'product.fluorescence.intensity','width':'13%','_column_name':'product_fluorescence_intensity','label':'FLUR','help':'Fluorescence Intensity','type':'many2one','name':'fluorescence_intensity_id','product_search_type':'boolean','on_change':'product_fluorescence_intensity_change'}, {'model':'product.lab','width':'8%','_column_name':'product_lab','label':'LAB','help':'Lab','type':'many2one','name':'lab_id','product_search_type':'boolean','on_change':'product_lab_change'}, {'model':'product.fancy.color','width':'15%','_column_name':'product_fancy_color','label':'FNC CLR','help':'Fancy Color','type':'many2one','name':'fancy_color_id','product_search_type':'boolean','on_change':'product_fancy_color_change'}, {'model':'product.fancy.color.intensity','width':'15%','_column_name':'product1_fancy_color_intensity','label':'FNC CLR INT','help':'Fancy Color Intensity','type':'many2one','name':'fancy_color_intensity','product_search_type':'boolean','on_change':'product1_fancy_color_intensity_change'}, {'model':'product.fancy.color.overtone','width':'15%','_column_name':'product2_fancy_color_overtone','label':'FNC CLR OVR','help':'Fancy Color Overtone','type':'many2one','name':'fancy_color_overtone','product_search_type':'boolean','on_change':'product2_fancy_color_overtone_change'}, {'model':None,'_column_name':'product_status','width':'20%','label':'Status','type':'selection','name':'product_status','product_search_type':'boolean' ,'selection_val':[('available','Available'), ('hold','Hold'), ('sold','Sold'), ('on_approval','On Approval'), ('on_consignment','On Consignment'), ('offline','Offline'), ('repair','Repair'), ('web_sale','Web Sale')]}, {'model':'stock.location','_column_name':'stock_location','width':'15%','label':'Location','type':'many2one','name':'location_id','product_search_type':'boolean' ,'domain':[('usage','=','internal')],}, ] for model_info in info : if model_info['type'] == 'many2one' and model_info['product_search_type'] == 'boolean' : if model_info['model']: ids = self.pool.get(model_info['model']).search(cr,uid,model_info.get('domain',[])) if ids : _moves_arch_lst += """<div style="float:left;width:%s;">"""%(model_info.get('width', '100%')) ''' Header ''' if model_info.get('label', False)=='Location': _moves_arch_lst += """<u><label style="color:rgb(124,123,173);font-weight:bold;" string="%s"/></u>"""%(model_info['label']) if model_info.get('on_change', False): ''' Check box for Select All ''' _moves_arch_lst += """<div><field name="%s" class="oe_inline" nolabel="1" on_change="%s(%s)"/> """%(model_info['on_change'],model_info['on_change'],model_info['on_change']) ''' Label for Select All ''' _moves_arch_lst += """<u><label help='%s' style="color:rgb(124, 123, 173);" string="%s" for="%s" /></u></div>"""%(model_info['help'],model_info['label'],model_info['label']) _line_fields.update({ '%s'%(model_info['on_change']) : { 'string': 'All ?', 'type' : 'boolean', },}) self._columns['%s'%(model_info['on_change'])] = fields.boolean(model_info['on_change']) for obj in self.pool.get(model_info['model']).browse(cr,uid,ids,context=context): name=len(obj.name) > 7 and (obj.name[:7]+'...') or obj.name[:7] _line_fields.update({ '%s%s'%(model_info['_column_name'],obj.id) : { 'string': obj.name, 'type' : 'boolean', 'help' : '%s'%(obj.name) },}) self._columns['%s%s'%(model_info['_column_name'],obj.id)] = fields.boolean(obj.name) ''' Check box and related label ''' _moves_arch_lst += """ <div><field name="%s%s" class="oe_inline" nolabel="1"/> <label string="%s" for="%s%s" /></div> """%(model_info['_column_name'],obj.id,name,model_info['_column_name'],obj.id) _moves_arch_lst += """</div>""" ####################### if model_info['type'] == 'char' and model_info['product_search_type'] == 'char': _moves_arch_lst += """<div style="width:%s;float:left;">""" %('50%') _line_fields.update({ '%s'%(model_info['_column_name']) : { 'string': 'Name', 'type' : 'char', 'help' : '%s'%(model_info['_column_name']), },}) self._columns['%s'%(model_info['_column_name'])] = fields.char(model_info['label'],size=1024) _moves_arch_lst += """ <div> <label style="color:rgb(124, 123, 173);" string="%s" for="%s" /> <field name="%s" style="width: 70%%" nolabel="1"/> </div> </div> """%(model_info['label'],model_info['_column_name'],model_info['_column_name']) ################################ if model_info['type'] == 'selection' and model_info['product_search_type'] == 'boolean' : if model_info['selection_val']: _moves_arch_lst += """<div style="float:left;width:%s">"""%(model_info['width']) _moves_arch_lst += """<u><label style="color:rgb(124, 123, 173);font-weight:bold;" string="%s" /></u><newline/>"""%(model_info['label']) for value in model_info['selection_val']: _line_fields.update({ '%s_%s'%(model_info['_column_name'],value[0]) : { 'string': value[1], 'type' : 'boolean', },}) self._columns['%s_%s'%(model_info['_column_name'],value[0])] = fields.boolean(value[1]) _moves_arch_lst += """ <div><field name="%s_%s" nolabel="1"/> <label string="%s" for="%s_%s" /></div> """%(model_info['_column_name'],value[0],value[1],model_info['_column_name'],value[0]) _moves_arch_lst +="""</div>""" ########################### if model_info.get('range') and model_info['range']: width = '50%' if model_info.get('no') > 1:width = '100%' _moves_arch_lst += """<div style="float:left;width:%s;">"""%(width) _moves_arch_lst += """<div style="float:left;width:%s;"><label style="color:rgb(124, 123, 173);font-weight:bold;" string="%s" /></div>"""%('15%',model_info['label']) if model_info.get('no'): no = model_info.get('no') wid = str(85/int(no)) + '%' while no != 0 : no = no - 1 _line_fields.update({'%s_from_%s'%(model_info['_column_name'],no) : {'string': model_info['label'],'type':'float'}}) _line_fields.update({'%s_to_%s'%(model_info['_column_name'],no) : {'string': model_info['label'],'type':'float'}}) self._columns['%s_from_%s'%(model_info['_column_name'],no)] = fields.float(model_info['label'],digits=(16,2)) self._columns['%s_to_%s'%(model_info['_column_name'],no)] = fields.float(model_info['label'],digits=(16,2)) _moves_arch_lst += """ <div style="float:left;width:%s;"> <div style="float:left;"><field name="%s_from_%s" placeholder="From" class="oe_inline" nolabel="1"/></div> <div style="float:left;"><b><label style="color:rgb(124, 123, 173);" string="--" /></b></div> <div style="float:left;"><field name="%s_to_%s" placeholder="To" class="oe_inline" nolabel="1"/></div> </div> """%(wid,model_info['_column_name'],no,model_info['_column_name'],no) _moves_arch_lst += """</div>""" _moves_arch_lst += """ </div> <footer> <button name="get_product" string="Search" type="object" colspan="2" class="oe_highlight"/> or <button string="Cancel" class="oe_link" special="cancel"/> </footer> </form> """ result['arch'] = _moves_arch_lst result['arch'] = result['arch'].replace('&','&') result['fields'] = _line_fields return result
class buying_postage(osv.osv_memory): _name = "buying.postage" _description = "Buying Postage" def action_buy_postge(self, cr, uid, ids, context=None): ship_endicia = self.pool.get('shipping.endicia').get_endicia_info(cr,uid,context) requester_id = ship_endicia.requester_id account_id = ship_endicia.account_id passphrase = ship_endicia.passphrase debug = ship_endicia.test tot_rate = self.browse(cr,uid,ids[0]).name if tot_rate < 10.00: raise osv.except_osv(_('Error'), _('You cannot buy postage less than $10')) try: request = endicia.RecreditRequest(requester_id, account_id, passphrase, tot_rate, debug=debug) response = request.send() buy_postage_resp = response._get_value() except Exception, e: raise osv.except_osv(_('Error'), _('Error buying postage')) message = _('Remaining postage balance: %s\nTotal amount of postage printed: %s' % (buy_postage_resp['postage_balance'], buy_postage_resp['postage_printed'])) self.log(cr, uid, ids[0], message) return {'type': 'ir.actions.act_window_close'} _columns = { 'name': fields.float('Total Rate'), } buying_postage()
#res[company.id]['smart_cash'] = 0.0 return res _columns = { 'smart_budget': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget',multi='all',help="Approved invoiced amount.",), # 'smart_cash': fields.function(smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget', # help="Approved invoiced amount.", # multi='all',), 'smart_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Cash', help="Free invoiced amount for salary or expenses.", multi='all',), 'prepayment': fields.boolean('Prepayment',help="SMart User: this virtual company can have prepayment smart_cash, SMart Company: this country applies prepayment"), 'prepayment_days': fields.integer('Prepayment Days',help="Leadtime in days before invoiced amount becomes smart_cash (global)"), 'smart_share': fields.float('SMarts Share',digits_compute=dp.get_precision('Account')), 'sale_order_sum_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum cash',multi='all',help="Approved invoiced amount.",), 'sale_order_sum_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum budget',multi='all',help="Approved invoiced amount.",), 'smart_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount cash',multi='all',help="Approved invoiced amount.",), 'smart_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount budget',multi='all',help="Approved invoiced amount.",), 'activity_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount cash',multi='all',help="Approved invoiced amount.",), 'activity_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount budget',multi='all',help="Approved invoiced amount.",), 'expense_sum_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart expense sum cash',multi='all',help="Approved invoiced amount.",), 'expense_sum_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart expense sum budget',multi='all',help="Approved invoiced amount.",), } _defaults = { 'prepayment': True, 'smart_cash': 0.0, 'smart_budget': 0.0, }
help="Computed as: Time Spent + Remaining Time.", store={ 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), 'progress': fields.function(_hours_get, method=True, string='Progress (%)', multi='hours', group_operator="avg", help="Computed as: Time Spent / Total Time.", store={ 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours', 'state'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), 'delay_hours': fields.function(_hours_get, method=True, string='Delay Hours', multi='hours', help="Computed as difference of the time estimated by the\ project manager and the real time to close the task.", store={ 'project.task': (lambda self, cr, uid, ids, c={}: ids, ['work_ids', 'remaining_hours', 'planned_hours'], 10), 'project.task.work': (_get_task, ['hours'], 10), }), 'cost_per_task': fields.float('Cost', readonly=True, help="Computed as: Hour Cost multiplied by Job Hours"), }
cr, uid, line.taxes_id, line.price, line.qty, line.product_id, line.back_order_id.partner_id ) cur = line.back_order_id.pricelist_id.currency_id res[line.id] = cur_obj.round(cr, uid, cur, taxes["total"]) return res def _get_uom_id(self, cr, uid, context=None): try: proxy = self.pool.get("ir.model.data") result = proxy.get_object_reference(cr, uid, "product", "product_uom_unit") return result[1] except Exception, ex: return False _columns = { # 'location_destination_id': fields.many2one('stock.location', 'Stock Destination Location'), # 'location_id': fields.many2one('stock.location', 'Stock Source Location'), "product_id": fields.many2one("product.product", "Product"), "back_order_id": fields.many2one("back.to.back.order", "Back Order"), "qty": fields.float("Quantity"), "price": fields.float("Unit Price"), "subtotal": fields.function(_amount_line, string="Subtotal", digits_compute=dp.get_precision("Account")), "taxes_id": fields.many2many("account.tax", "purchase_order_taxe", "ord_id", "tax_id", "Taxes"), "product_uom": fields.many2one("product.uom", "Product Unit of Measure", required=True), } _defaults = {"product_uom": _get_uom_id} # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class crm_claim(orm.Model): _inherit = 'crm.claim' _columns = { 'number': fields.char('Number', size=128, readonly=True, states={'draft': [('readonly', False)]}, required=True, help="Company internal claim unique number"), 'claim_type': fields.selection( [('customer', 'Customer'), ('supplier', 'Supplier'), ('other', 'Other')], 'Claim type', required=True, help= "customer = from customer to company ; supplier = from company to supplier" ), 'claim_line_ids': fields.one2many('claim.line', 'claim_id', 'Return lines'), 'product_exchange_ids': fields.one2many('product.exchange', 'claim_return_id', 'Product exchanges'), # Aftersale outsourcing # 'in_supplier_picking_id': fields.many2one('stock.picking', 'Return To Supplier Picking', required=False, select=True), # 'out_supplier_picking_id': fields.many2one('stock.picking', 'Return From Supplier Picking', required=False, select=True), # Financial management 'planned_revenue': fields.float('Expected revenue'), 'planned_cost': fields.float('Expected cost'), 'real_revenue': fields.float('Real revenue'), 'real_cost': fields.float('Real cost'), 'invoice_ids': fields.one2many('account.invoice', 'claim_id', 'Refunds'), 'picking_ids': fields.one2many('stock.picking', 'claim_id', 'RMA'), 'invoice_id': fields.many2one('account.invoice', 'Invoice', help='Related invoice'), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True), } _defaults = { 'number': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get( cr, uid, 'crm.claim'), 'claim_type': lambda *a: 'customer', 'warehouse_id': lambda *a: 1, } def onchange_partner_address_id(self, cr, uid, ids, add, email=False, context=None): res = super(crm_claim, self).onchange_partner_address_id(cr, uid, ids, add, email=email) if add: if not res['value']['email_from'] or not res['value'][ 'partner_phone']: address = self.pool.get('res.partner').browse(cr, uid, add) for other_add in address.partner_id.address: if other_add.email and not res['value']['email_from']: res['value']['email_from'] = other_add.email if other_add.phone and not res['value']['partner_phone']: res['value']['partner_phone'] = other_add.phone return res def onchange_invoice_id(self, cr, uid, ids, invoice_id, context=None): invoice_line_obj = self.pool.get('account.invoice.line') invoice_line_ids = invoice_line_obj.search( cr, uid, [('invoice_id', '=', invoice_id)]) claim_lines = [] for invoice_line in invoice_line_obj.browse(cr, uid, invoice_line_ids): # claim_line_obj = self.pool.get('claim.line') claim_lines.append({ 'name': invoice_line.name, 'claim_origine': "none", 'invoice_line_id': invoice_line.id, 'product_id': invoice_line.product_id.id, 'product_returned_quantity': invoice_line.quantity, 'unit_sale_price': invoice_line.price_unit, # 'prodlot_id' : invoice_line., 'state': 'draft', }) # for line in claim_line_obj.browse(cr,uid,[line_id],context): # line.set_warranty() return {'value': {'claim_line_ids': claim_lines}}
class PaymentAcquirer(osv.Model): """ Acquirer Model. Each specific acquirer can extend the model by adding its own fields, using the acquirer_name as a prefix for the new fields. Using the required_if_provider='<name>' attribute on fields it is possible to have required fields that depend on a specific acquirer. Each acquirer has a link to an ir.ui.view record that is a template of a button used to display the payment form. See examples in ``payment_ogone`` and ``payment_paypal`` modules. Methods that should be added in an acquirer-specific implementation: - ``<name>_form_generate_values(self, cr, uid, id, reference, amount, currency, partner_id=False, partner_values=None, tx_custom_values=None, context=None)``: method that generates the values used to render the form button template. - ``<name>_get_form_action_url(self, cr, uid, id, context=None):``: method that returns the url of the button form. It is used for example in ecommerce application, if you want to post some data to the acquirer. - ``<name>_compute_fees(self, cr, uid, id, amount, currency_id, country_id, context=None)``: computed the fees of the acquirer, using generic fields defined on the acquirer model (see fields definition). Each acquirer should also define controllers to handle communication between OpenERP and the acquirer. It generally consists in return urls given to the button form and that the acquirer uses to send the customer back after the transaction, with transaction details given as a POST request. """ _name = 'payment.acquirer' _description = 'Payment Acquirer' _order = 'sequence' def _get_providers(self, cr, uid, context=None): return [] # indirection to ease inheritance _provider_selection = lambda self, *args, **kwargs: self._get_providers(*args, **kwargs) _columns = { 'name': fields.char('Name', required=True), 'provider': fields.selection(_provider_selection, string='Provider', required=True), 'company_id': fields.many2one('res.company', 'Company', required=True), 'pre_msg': fields.html('Message', translate=True, help='Message displayed to explain and help the payment process.'), 'post_msg': fields.html('Thanks Message', help='Message displayed after having done the payment process.'), 'validation': fields.selection( [('manual', 'Manual'), ('automatic', 'Automatic')], string='Process Method', help='Static payments are payments like transfer, that require manual steps.'), 'view_template_id': fields.many2one('ir.ui.view', 'Form Button Template', required=True), 'environment': fields.selection( [('test', 'Test'), ('prod', 'Production')], string='Environment', oldname='env'), 'website_published': fields.boolean( 'Visible in Portal / Website', copy=False, help="Make this payment acquirer available (Customer invoices, etc.)"), 'auto_confirm': fields.selection( [('none', 'No automatic confirmation'), ('at_pay_confirm', 'At payment confirmation'), ('at_pay_now', 'At payment')], string='Order Confirmation', required=True), # Fees 'fees_active': fields.boolean('Compute fees'), 'fees_dom_fixed': fields.float('Fixed domestic fees'), 'fees_dom_var': fields.float('Variable domestic fees (in percents)'), 'fees_int_fixed': fields.float('Fixed international fees'), 'fees_int_var': fields.float('Variable international fees (in percents)'), 'sequence': fields.integer('Sequence', help="Determine the display order"), } _defaults = { 'company_id': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(cr, uid, uid).company_id.id, 'environment': 'test', 'validation': 'automatic', 'website_published': True, 'auto_confirm': 'at_pay_confirm', } def _check_required_if_provider(self, cr, uid, ids, context=None): """ If the field has 'required_if_provider="<provider>"' attribute, then it required if record.provider is <provider>. """ for acquirer in self.browse(cr, uid, ids, context=context): if any(getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k] for k, f in self._fields.items()): return False return True _constraints = [ (_check_required_if_provider, 'Required fields not filled', ['required for this provider']), ] def get_form_action_url(self, cr, uid, id, context=None): """ Returns the form action URL, for form-based acquirer implementations. """ acquirer = self.browse(cr, uid, id, context=context) if hasattr(self, '%s_get_form_action_url' % acquirer.provider): return getattr(self, '%s_get_form_action_url' % acquirer.provider)(cr, uid, id, context=context) return False def form_preprocess_values(self, cr, uid, id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_values, context=None): """ Pre process values before giving them to the acquirer-specific render methods. Those methods will receive: - partner_values: will contain name, lang, email, zip, address, city, country_id (int or False), country (browse or False), phone, reference - tx_values: will contain reference, amount, currency_id (int or False), currency (browse or False), partner (browse or False) """ acquirer = self.browse(cr, uid, id, context=context) if tx_id: tx = self.pool.get('payment.transaction').browse(cr, uid, tx_id, context=context) tx_data = { 'reference': tx.reference, 'amount': tx.amount, 'currency_id': tx.currency_id.id, 'currency': tx.currency_id, 'partner': tx.partner_id, } partner_data = { 'name': tx.partner_name, 'lang': tx.partner_lang, 'email': tx.partner_email, 'zip': tx.partner_zip, 'address': tx.partner_address, 'city': tx.partner_city, 'country_id': tx.partner_country_id.id, 'country': tx.partner_country_id, 'phone': tx.partner_phone, 'reference': tx.partner_reference, 'state': None, } else: if partner_id: partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) partner_data = { 'name': partner.name, 'lang': partner.lang, 'email': partner.email, 'zip': partner.zip, 'city': partner.city, 'address': _partner_format_address(partner.street, partner.street2), 'country_id': partner.country_id.id, 'country': partner.country_id, 'phone': partner.phone, 'state': partner.state_id, } else: partner, partner_data = False, {} partner_data.update(partner_values) if currency_id: currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context) else: currency = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id tx_data = { 'reference': reference, 'amount': amount, 'currency_id': currency.id, 'currency': currency, 'partner': partner, } # update tx values tx_data.update(tx_values) # update partner values if not partner_data.get('address'): partner_data['address'] = _partner_format_address(partner_data.get('street', ''), partner_data.get('street2', '')) if not partner_data.get('country') and partner_data.get('country_id'): partner_data['country'] = self.pool['res.country'].browse(cr, uid, partner_data.get('country_id'), context=context) partner_data.update({ 'first_name': _partner_split_name(partner_data['name'])[0], 'last_name': _partner_split_name(partner_data['name'])[1], }) # compute fees fees_method_name = '%s_compute_fees' % acquirer.provider if hasattr(self, fees_method_name): fees = getattr(self, fees_method_name)( cr, uid, id, tx_data['amount'], tx_data['currency_id'], partner_data['country_id'], context=None) tx_data['fees'] = float_round(fees, 2) return (partner_data, tx_data) def render(self, cr, uid, id, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_values=None, context=None): """ Renders the form template of the given acquirer as a qWeb template. All templates will receive: - acquirer: the payment.acquirer browse record - user: the current user browse record - currency_id: id of the transaction currency - amount: amount of the transaction - reference: reference of the transaction - partner: the current partner browse record, if any (not necessarily set) - partner_values: a dictionary of partner-related values - tx_values: a dictionary of transaction related values that depends on the acquirer. Some specific keys should be managed in each provider, depending on the features it offers: - 'feedback_url': feedback URL, controler that manage answer of the acquirer (without base url) -> FIXME - 'return_url': URL for coming back after payment validation (wihout base url) -> FIXME - 'cancel_url': URL if the client cancels the payment -> FIXME - 'error_url': URL if there is an issue with the payment -> FIXME - context: OpenERP context dictionary :param string reference: the transaction reference :param float amount: the amount the buyer has to pay :param res.currency browse record currency: currency :param int tx_id: id of a transaction; if set, bypasses all other given values and only render the already-stored transaction :param res.partner browse record partner_id: the buyer :param dict partner_values: a dictionary of values for the buyer (see above) :param dict tx_custom_values: a dictionary of values for the transction that is given to the acquirer-specific method generating the form values :param dict context: OpenERP context """ if context is None: context = {} if tx_values is None: tx_values = {} if partner_values is None: partner_values = {} acquirer = self.browse(cr, uid, id, context=context) # pre-process values amount = float_round(amount, 2) partner_values, tx_values = self.form_preprocess_values( cr, uid, id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_values, context=context) # call <name>_form_generate_values to update the tx dict with acqurier specific values cust_method_name = '%s_form_generate_values' % (acquirer.provider) if hasattr(self, cust_method_name): method = getattr(self, cust_method_name) partner_values, tx_values = method(cr, uid, id, partner_values, tx_values, context=context) qweb_context = { 'tx_url': context.get('tx_url', self.get_form_action_url(cr, uid, id, context=context)), 'submit_class': context.get('submit_class', 'btn btn-link'), 'submit_txt': context.get('submit_txt'), 'acquirer': acquirer, 'user': self.pool.get("res.users").browse(cr, uid, uid, context=context), 'reference': tx_values['reference'], 'amount': tx_values['amount'], 'currency': tx_values['currency'], 'partner': tx_values.get('partner'), 'partner_values': partner_values, 'tx_values': tx_values, 'context': context, } # because render accepts view ids but not qweb -> need to use the xml_id return self.pool['ir.ui.view'].render(cr, uid, acquirer.view_template_id.xml_id, qweb_context, engine='ir.qweb', context=context) def _wrap_payment_block(self, cr, uid, html_block, amount, currency_id, context=None): payment_header = _('Pay safely online') amount_str = float_repr(amount, self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')) currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context) currency_str = currency.symbol or currency.name amount = u"%s %s" % ((currency_str, amount_str) if currency.position == 'before' else (amount_str, currency_str)) result = u"""<div class="payment_acquirers"> <div class="payment_header"> <div class="payment_amount">%s</div> %s </div> %%s </div>""" % (amount, payment_header) return result % html_block.decode("utf-8") def render_payment_block(self, cr, uid, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_values=None, company_id=None, context=None): html_forms = [] domain = [('website_published', '=', True), ('validation', '=', 'automatic')] if company_id: domain.append(('company_id', '=', company_id)) acquirer_ids = self.search(cr, uid, domain, context=context) for acquirer_id in acquirer_ids: button = self.render( cr, uid, acquirer_id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_values, context) html_forms.append(button) if not html_forms: return '' html_block = '\n'.join(filter(None, html_forms)) return self._wrap_payment_block(cr, uid, html_block, amount, currency_id, context=context)
res = super(account_voucher, self).onchange_amount(cr, uid, ids, amount, rate, partner_id, journal_id, currency_id, ttype, date, payment_rate_currency_id, company_id, context=context) res['value'].update({'cc_order_amt':amount, 'cc_refund_amt':amount}) return res _inherit = 'account.voucher' _columns = { 'cc_name':fields.char("Card Holder's Name", size=32,), 'cc_b_addr_1':fields.char('Billing Address1', size=32,), 'cc_b_addr_2':fields.char('Billing Address2', size=32,), 'cc_city': fields.char('City', size=32,), 'cc_state':fields.char('State', size=32,), 'cc_zip':fields.char('Postal/Zip', size=32,), 'cc_country':fields.char('Country', size=32,), 'cc_order_date':fields.date('Order Date',), <<<<<<< HEAD 'cc_order_amt':fields.float('Order Amt'), ======= 'cc_order_amt':fields.float('Order Amt',required=True), >>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d 'cc_number':fields.char('Credit Card Number', size=256), 'cc_v':fields.char('Card Code Verification', size=3), 'cc_e_d_month':fields.char('Expiration Date MM', size=32), 'cc_e_d_year':fields.char('Expiration Date YY', size=32), 'cc_comment':fields.char('Comment', size=128,), 'cc_auth_code':fields.char('Authorization Code', size=32), 'cc_save_card_details':fields.boolean('Save Credit Card details'), 'cc_ecommerce_sale':fields.boolean('Ecommerce sale'), 'cc_p_authorize':fields.boolean('Pre-authorize'), 'cc_charge':fields.boolean('Charge'), 'cc_info_hide':fields.boolean('Credit Info Hide'), 'cc_status':fields.text('Status Message'),
class claim_line(orm.Model): """ Class to handle a product return line (corresponding to one invoice line) """ _name = "claim.line" _description = "List of product to return" # Method to calculate total amount of the line : qty*UP def _line_total_amount(self, cr, uid, ids, field_name, arg, context=None): res = {} for line in self.browse(cr, uid, ids): res[line. id] = line.unit_sale_price * line.product_returned_quantity return res _columns = { 'name': fields.char('Description', size=64, required=True), 'claim_origine': fields.selection([('none', 'Not specified'), ('legal', 'Legal retractation'), ('cancellation', 'Order cancellation'), ('damaged', 'Damaged delivered product'), ('error', 'Shipping error'), ('exchange', 'Exchange request'), ('lost', 'Lost during transport'), ('other', 'Other')], 'Claim Subject', required=True, help="To describe the line product problem"), 'claim_descr': fields.text('Claim description', help="More precise description of the problem"), 'product_id': fields.many2one('product.product', 'Product', help="Returned product"), 'product_returned_quantity': fields.float('Quantity', digits=(12, 2), help="Quantity of product returned"), 'unit_sale_price': fields.float( 'Unit sale price', digits=(12, 2), help= "Unit sale price of the product. Auto filed if retrun done by invoice selection. BE CAREFUL AND CHECK the automatic value as don't take into account previous refounds, invoice discount, can be for 0 if product for free,..." ), 'return_value': fields.function( _line_total_amount, method=True, string='Total return', type='float', help="Quantity returned * Unit sold price", ), 'prodlot_id': fields.many2one('stock.production.lot', 'Serial/Lot n°', help="The serial/lot of the returned product"), 'applicable_guarantee': fields.selection( [('us', 'Company'), ('supplier', 'Supplier'), ('brand', 'Brand manufacturer')], 'Warranty type' ), # TODO: Replace with function field. type supplier might generate an auto draft forward to the supplier 'guarantee_limit': fields.date( 'Warranty limit', help= "The warranty limit is computed as: invoice date + warranty defined on selected product.", readonly=True), 'warning': fields.char('Warranty', size=64, readonly=True, help="If warranty has expired"), 'warranty_type': fields.char('Warranty type', size=64, readonly=True, help="from product form"), "warranty_return_partner": fields.many2one( 'res.partner', 'Warranty return', help="Where the customer has to send back the product(s)"), 'claim_id': fields.many2one('crm.claim', 'Related claim', help="To link to the case.claim object"), 'state': fields.selection([('draft', 'Draft'), ('refused', 'Refused'), ('confirmed', 'Confirmed, waiting for product'), ('in_to_control', 'Received, to control'), ('in_to_treate', 'Controlled, to treate'), ('treated', 'Treated')], 'State'), 'substate_id': fields.many2one( 'substate.substate', 'Sub state', help= "Select a sub state to precise the standard state. Example 1: state = refused; substate could be warranty over, not in warranty, no problem,... . Example 2: state = to treate; substate could be to refund, to exchange, to repair,..." ), 'last_state_change': fields.date('Last change', help="To set the last state / substate change"), 'invoice_line_id': fields.many2one( 'account.invoice.line', 'Invoice Line', help='The invoice line related to the returned product'), 'refund_line_id': fields.many2one( 'account.invoice.line', 'Refund Line', help='The refund line related to the returned product'), 'move_in_id': fields.many2one('stock.move', 'Move Line from picking in', help='The move line related to the returned product'), 'move_out_id': fields.many2one('stock.move', 'Move Line from picking out', help='The move line related to the returned product'), } _defaults = { 'state': lambda *a: 'draft', 'name': lambda *a: 'none', } # Method to calculate warranty limit def set_warranty_limit(self, cr, uid, ids, claim_line, context=None): date_invoice = claim_line.invoice_line_id.invoice_id.date_invoice if date_invoice: warning = "Valid" if claim_line.claim_id.claim_type == 'supplier': if claim_line.prodlot_id: limit = ( datetime.strptime(date_invoice, DEFAULT_SERVER_DATE_FORMAT) + relativedelta( months=int(claim_line.product_id.seller_ids[0]. warranty_duration)) ).strftime( DEFAULT_SERVER_DATE_FORMAT) # TODO: To be implemented else: limit = (datetime.strptime(date_invoice, DEFAULT_SERVER_DATE_FORMAT) + relativedelta( months=int(claim_line.product_id. seller_ids[0].warranty_duration)) ).strftime(DEFAULT_SERVER_DATE_FORMAT) else: limit = ( datetime.strptime(date_invoice, DEFAULT_SERVER_DATE_FORMAT) + relativedelta(months=int(claim_line.product_id.warranty)) ).strftime(DEFAULT_SERVER_DATE_FORMAT) if limit < claim_line.claim_id.date: warning = 'Expired' self.write(cr, uid, ids, { 'guarantee_limit': limit, 'warning': warning, }) else: raise osv.except_osv( _('Error !'), _('Cannot find any date for invoice ! Must be a validated invoice !' )) return True # Method to calculate warranty return address def set_warranty_return_address(self, cr, uid, ids, claim_line, context=None): return_address = None warranty_type = 'company' seller = claim_line.product_id.seller_info_id if seller: return_partner = seller.warranty_return_partner if return_partner: warranty_type = return_partner else: warranty_type = 'company' return_address = seller.warranty_return_address.id # if return_partner == 'company': # return_address = self._get_partner_address(cr, uid, ids, context,claim_line.claim_id.company_id.partner_id)[0] # elif return_partner == 'supplier': # return_address = self._get_partner_address(cr, uid, ids, context,claim_line.product_id.seller_ids[0].name)[0] # warranty_type = 'supplier' # elif return_partner == 'brand': # return_address = self._get_partner_address(cr, uid, ids, context, claim_line.product_id.product_brand_id.partner_id)[0] # warranty_type = 'brand' # else : # warranty_type = 'other' # # TO BE IMPLEMENTED if something to do... # else : # warranty_type = 'company' # return_address = self._get_default_company_address(cr, uid, claim_line.claim_id.company_id, context=context) #TODO fix me use default address # self.write(cr,uid,ids,{'warranty_return_partner':1,'warranty_type': 'company'}) # return True #raise osv.except_osv(_('Error !'), _('Cannot find any warranty return partner for this product !')) else: warranty_type = 'company' if claim_line.claim_id.company_id.crm_return_address_id: return_address = [ claim_line.claim_id.company_id.crm_return_address_id.id ] else: return_address = [ claim_line.claim_id.company_id.partner_id.address[0].id ] # return_address = self._get_default_company_address(cr, uid, claim_line.claim_id.company_id, context=context) #TODO fix me use default address # self.write(cr,uid,ids,{'warranty_return_partner':1,'warranty_type': 'company'}) # return True #raise osv.except_osv(_('Error !'), _('Cannot find any supplier for this product !')) self.write( cr, uid, ids, { 'warranty_return_partner': return_address, 'warranty_type': warranty_type }) return True # Method to calculate warranty limit and validity def set_warranty(self, cr, uid, ids, context=None): for claim_line in self.browse(cr, uid, ids, context=context): if claim_line.product_id and claim_line.invoice_line_id: self.set_warranty_limit(cr, uid, ids, claim_line, context) self.set_warranty_return_address(cr, uid, ids, claim_line, context) else: raise osv.except_osv(_('Error !'), _('PLEASE SET PRODUCT & INVOICE!')) return True
"sequence": fields.integer("Sequence"), "product_id": fields.many2one( "product.product", "Product", domain=[("is_rent", "=", True)], change_default=True ), "invoice_lines": fields.many2many( "account.invoice.line", "rent_order_line_invoice_rel", "order_line_id", "invoice_id", "Invoice Lines", readonly=True, ), "price_unit": fields.float( "Unit Price", required=True, digits_compute=dp.get_precision("Product Price"), readonly=True, states={"draft": [("readonly", False)]}, ), "price_subtotal": fields.function(_amount_line, string="Subtotal", digits_compute=dp.get_precision("Account")), "tax_id": fields.many2many( "account.tax", "rent_order_tax", "order_line_id", "tax_id", "Taxes", readonly=True, states={"draft": [("readonly", False)]}, ), "product_uom_qty": fields.float( "Quantity",
class hr_expense_line(osv.osv): _name = "hr.expense.line" _description = "Expense Line" def _amount(self, cr, uid, ids, field_name, arg, context=None): if not ids: return {} cr.execute( "SELECT l.id,COALESCE(SUM(l.unit_amount*l.unit_quantity),0) AS amount FROM hr_expense_line l WHERE id IN %s GROUP BY l.id ", (tuple(ids), )) res = dict(cr.fetchall()) return res def _get_uom_id(self, cr, uid, context=None): result = self.pool.get('ir.model.data').get_object_reference( cr, uid, 'product', 'product_uom_unit') return result and result[1] or False _columns = { 'name': fields.char('Expense Note', required=True), 'date_value': fields.date('Date', required=True), 'expense_id': fields.many2one('hr.expense.expense', 'Expense', ondelete='cascade', select=True), 'total_amount': fields.function(_amount, string='Total', digits_compute=dp.get_precision('Account')), 'unit_amount': fields.float('Unit Price', digits_compute=dp.get_precision('Product Price')), 'unit_quantity': fields.float( 'Quantities', digits_compute=dp.get_precision('Product Unit of Measure')), 'product_id': fields.many2one('product.product', 'Product', domain=[('hr_expense_ok', '=', True)]), 'uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True), 'description': fields.text('Description'), 'analytic_account': fields.many2one('account.analytic.account', 'Analytic account'), 'ref': fields.char('Reference'), 'sequence': fields.integer( 'Sequence', select=True, help= "Gives the sequence order when displaying a list of expense lines." ), } _defaults = { 'unit_quantity': 1, 'date_value': lambda *a: time.strftime('%Y-%m-%d'), 'uom_id': _get_uom_id, } _order = "sequence, date_value desc" def onchange_product_id(self, cr, uid, ids, product_id, context=None): res = {} if product_id: product = self.pool.get('product.product').browse(cr, uid, product_id, context=context) res['name'] = product.name amount_unit = product.price_get('standard_price')[product.id] res['unit_amount'] = amount_unit res['uom_id'] = product.uom_id.id return {'value': res} def onchange_uom(self, cr, uid, ids, product_id, uom_id, context=None): res = {'value': {}} if not uom_id or not product_id: return res product = self.pool.get('product.product').browse(cr, uid, product_id, context=context) uom = self.pool.get('product.uom').browse(cr, uid, uom_id, context=context) if uom.category_id.id != product.uom_id.category_id.id: res['warning'] = { 'title': _('Warning'), 'message': _('Selected Unit of Measure does not belong to the same category as the product Unit of Measure' ) } res['value'].update({'uom_id': product.uom_id.id}) return res
class account_caja_chica(osv.osv): _order = "date desc, id desc" _name = "account.caja.chica" _description = "Caja Chica" # _inherit = ['mail.thread'] def _get_default_company(self, cr, uid, context=None): company_id = self.pool.get('res.users')._get_company(cr, uid, context=context) if not company_id: raise osv.except_osv( _('Error!'), _('There is no default company for the current user!')) return company_id _columns = { 'name': fields.char( 'Referencia', states={'draft': [('readonly', False)]}, readonly=True, # readonly for account_cash_statement copy=False, help= 'if you give the Name other then /, its created Accounting Entries Move ' 'will be with same name as statement name. ' 'This allows the statement entries to have the same references than the ' 'statement itself'), 'date': fields.date('Fecha Caja', required=True, states={'confirm': [('readonly', True)]}, select=True, copy=False), 'date_cierre': fields.date('Fecha Cierre', states={'draft': [('readonly', True)]}, select=True, copy=False), 'user_id': fields.many2one('res.users', 'Responsable', states={ 'draft': [('readonly', False)], 'open': [('readonly', False)] }, select=True, track_visibility='onchange'), 'saldo_ini': fields.float('Saldo Inicial', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'saldo_pend': fields.float('Saldo Pendiente', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_bruto': fields.float('Valor Bruto', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_neto': fields.float('Neto Pagar', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_iva': fields.float('Valor Iva', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_bruto_f': fields.float('Valor Bruto F', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_neto_f': fields.float('Neto Pagar F', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'valor_iva_f': fields.float('Valor Iva F', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'company_id': fields.related('company_id', type='many2one', relation='res.company', string='Compañia', store=True, readonly=True), #'company_id': fields.many2one('res.company', 'Company'), 'line_ids': fields.one2many('account.caja.chica.line', 'caja_chica_id', 'Caja chica lines', states={'confirm': [('readonly', True)]}, copy=True), 'state': fields.selection( [ ('draft', 'New'), ('open', 'Open'), # CSV:2016-04-21 used by cash statements ('pending', 'Pendiente'), # CSV:2016-04-21 used by pay partial ('confirm', 'Closed') ], 'Status', required=True, readonly="1", copy=False, help='When new statement is created the status will be \'Draft\'.\n' 'And after getting confirmation from the bank it will be in \'Confirmed\' status.' ), } _defaults = { 'name': 'Caja Chica/', 'date': fields.date.context_today, 'state': 'draft', #'company_id': _get_default_company, 'company_id': lambda self, cr, uid, c: self.pool.get('res.company'). _company_default_get(cr, uid, 'account.caja.chica', context=c), 'user_id': lambda obj, cr, uid, context: uid, } def cerrar_caja(self, cr, uid, ids, context=None): lis_rec = [] band = 0 obj_caja = self.browse(cr, uid, ids)[0] self.write(cr, uid, ids, {'state': 'pending'}) #Creo un registro de caja nuevo con el saldo pendiente como inicial para la nueva caja data = { 'name': obj_caja.name, 'user_id': obj_caja.user_id.id, 'date': time.strftime('%Y-%m-%d %H:%M:%S'), 'company_id': obj_caja.company_id.id, 'saldo_ini': obj_caja.saldo_pend, 'state': 'draft', } self.create(cr, uid, data, context) return True def validar_caja(self, cr, uid, ids, context=None): band = 0 lis_rec = [] invoice_id = False obj_caja = self.browse(cr, uid, ids)[0] self.write(cr, uid, ids, { 'state': 'confirm', 'date_cierre': time.strftime('%Y-%m-%d %H:%M:%S') }) inv_obj = self.pool.get('account.invoice') acc_jour_obj = self.pool.get('account.journal') inv_line_obj = self.pool.get('account.invoice.line') cchica_lin_obj = self.pool.get('account.caja.chica.line') cchica_line_ids = cchica_lin_obj.search( cr, uid, [('caja_chica_id', '=', obj_caja.id)], order='id, number_fact') stat_conc_line_obj = cchica_lin_obj.browse(cr, uid, cchica_line_ids, context=context) # JJM 2018-02-15 utilizo el superuser_id por que se necesita validar cajas chicas de otras companias # evito regla de registro para account_journal sobre company_id journal_id = acc_jour_obj.search( cr, SUPERUSER_ID, [('code', '=', 'DCC'), ('company_id', '=', obj_caja.company_id.id)]) if not journal_id: raise osv.except_osv( _('Advertencia!'), _('Primero debe crear un diario de caja chica para esta compania con codigo DCC!' )) journal_obj = acc_jour_obj.browse(cr, uid, journal_id, context=context) for ji in journal_obj: id_journal = ji.id num_comp = '' for det_cc in stat_conc_line_obj: #CONDICION SI ES COMPROBANTE TIPO FACTURA #print "LINEAS ID", det_cc.id #print "LINEAS", det_cc.product_id.name # JJM 2017-01-28 comento siguiente linea, ahora tomo cuenta desde la compañia #account_id = self.pool.get('multi.account.partner.rel').search(cr, uid, [('partner_id', '=', det_cc.partner_id.id), # ('type', '=', 'payable'), # ('company_id', '=', det_cc.company_id.id)]) if not det_cc.partner_id: raise osv.except_orm( 'Advertencia!', 'Debe ingresar un proveedor para la linea de %s' % (det_cc.name)) if len(det_cc.company_id.payable_ids) == 0: raise osv.except_orm( 'Advertencia!', 'La compania %s no tiene configurada la cuenta a pagar Proveedores' % det_cc.company_id.name) # JJM ahora tomo la cuenta desde la compañia en lugar del multi.account account_id = det_cc.company_id.payable_ids[0].id #account_id = self.pool.get('multi.account.partner.rel').browse(cr, uid, account_id[0]).property_account.id if not det_cc.sudo( det_cc.user_id).product_id.property_account_expense: raise osv.except_orm( 'Advertencia!', 'No tiene configurada la cuenta de gastos para el producto %s' % (det_cc.product_id.name)) if det_cc.cantidad <= 0: raise osv.except_orm( 'Advertencia!', 'la cantidad del producto %s no puede ser cero' % (det_cc.product_id.name)) if det_cc.tipo_comp == 'factura': #CREO REGISTRO NUEVO SOLO SI ES COMPROBANTE DIFERENTE if det_cc.tipo_comp == 'factura' and det_cc.number_fact != num_comp: num_comp = det_cc.number_fact #Creo cabecera Factura vals_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'journal_id': id_journal, 'number_seq': det_cc.number_fact, 'account_id': account_id, 'partner_id': det_cc.partner_id.id, 'company_id': det_cc.company_id.id, 'reference': det_cc.name, 'type': 'in_invoice', 'document_type': 1, 'is_cchica': True, 'is_asum': True, 'is_inv_elect': False, 'date_invoice': time.strftime('%Y-%m-%d %H:%M:%S'), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'state': 'draft' } print "DICCIO FACT", vals_invoice invoice_id = inv_obj.create(cr, uid, vals_invoice, context=context) #Creo detalle Factura if invoice_id: vals_det_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'invoice_id': invoice_id, 'company_id': det_cc.company_id.id, 'partner_id': det_cc.partner_id.id, 'product_id': det_cc.product_id.id, 'quantity': det_cc.cantidad, 'account_id': det_cc.sudo(det_cc.user_id).product_id. property_account_expense.id, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'price_subtotal': round(det_cc.amount_neto / det_cc.cantidad, 2), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), } invoice_line_id = inv_line_obj.create( cr, uid, vals_det_invoice) # CREO UNA LINEA MAS NADA MAS PORQUE ES DE LA MISMA FACTURA elif det_cc.tipo_comp == 'factura' and det_cc.number_fact == num_comp: num_comp = det_cc.number_fact #Creo detalle Factura if invoice_id: vals_det_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'invoice_id': invoice_id, 'company_id': det_cc.company_id.id, 'partner_id': det_cc.partner_id.id, 'product_id': det_cc.product_id.id, 'quantity': det_cc.cantidad, 'account_id': det_cc.sudo(det_cc.user_id).product_id. property_account_expense.id, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'price_subtotal': round(det_cc.amount_neto / det_cc.cantidad, 2), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), } invoice_line_id = inv_line_obj.create( cr, uid, vals_det_invoice) #CONDICION SI ES COMPROBANTE TIPO NOTA VENTA elif det_cc.tipo_comp == 'nventa': #CREO REGISTRO NUEVO SOLO SI ES COMPROBANTE DIFERENTE if det_cc.tipo_comp == 'nventa' and det_cc.number_fact != num_comp: num_comp = det_cc.number_fact #Creo cabecera COMPROBANTE TIPO NOTA VENTA vals_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'journal_id': id_journal, 'number_seq': det_cc.number_fact, 'account_id': account_id, 'partner_id': det_cc.partner_id.id, 'company_id': det_cc.company_id.id, 'reference': det_cc.name, 'type': 'in_invoice', 'document_type': 2, 'is_cchica': True, 'is_asum': True, 'is_inv_elect': False, 'date_invoice': time.strftime('%Y-%m-%d %H:%M:%S'), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'state': 'draft' } invoice_id = inv_obj.create(cr, uid, vals_invoice, context=context) #Creo detalle COMPROBANTE TIPO NOTA VENTA if invoice_id: vals_det_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'invoice_id': invoice_id, 'company_id': det_cc.company_id.id, 'partner_id': det_cc.partner_id.id, 'product_id': det_cc.product_id.id, 'quantity': det_cc.cantidad, 'account_id': det_cc.sudo(det_cc.user_id).product_id. property_account_expense.id, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'price_subtotal': round(det_cc.amount_neto / det_cc.cantidad, 2), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), } invoice_line_id = inv_line_obj.create( cr, uid, vals_det_invoice) # CREO UNA LINEA MAS NADA MAS PORQUE ES DE LA MISMO COMPROBANTE TIPO NOTA VENTA elif det_cc.tipo_comp == 'nventa' and det_cc.number_fact == num_comp: num_comp = det_cc.number_fact #Creo detalle COMPROBANTE TIPO NOTA VENTA if invoice_id: vals_det_invoice = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'invoice_id': invoice_id, 'company_id': det_cc.company_id.id, 'partner_id': det_cc.partner_id.id, 'product_id': det_cc.product_id.id, 'quantity': det_cc.cantidad, 'account_id': det_cc.sudo(det_cc.user_id).product_id. property_account_expense.id, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'price_subtotal': round(det_cc.amount_neto / det_cc.cantidad, 2), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), } invoice_line_id = inv_line_obj.create( cr, uid, vals_det_invoice) else: vals_recibo = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'journal_id': id_journal, 'account_id': account_id, 'partner_id': det_cc.partner_id.id, 'company_id': det_cc.company_id.id, 'reference': det_cc.name, 'date_invoice': time.strftime('%Y-%m-%d %H:%M:%S'), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), 'product_id': det_cc.product_id.id, 'quantity': det_cc.cantidad, 'account_line_id': det_cc.sudo( det_cc.user_id).product_id.property_account_expense.id, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'price_subtotal': round(det_cc.amount_neto / det_cc.cantidad, 2) } lis_rec.append(vals_recibo) band = 1 if band == 1: band1 = 0 for inv_rec in lis_rec: #Creo cabecera Factura if band1 == 0: vals_invoice = { 'name': inv_rec.get('name'), #'journal_id': det_cc.journal_id.id, 'account_id': inv_rec.get('account_id'), 'partner_id': inv_rec.get('partner_id'), 'company_id': inv_rec.get('company_id'), 'reference': inv_rec.get('reference'), 'type': 'in_invoice', 'document_type': 3, 'is_cchica': True, 'is_asum': True, 'is_inv_elect': False, 'date_invoice': inv_rec.get('date_invoice'), 'origin': inv_rec.get('origin'), 'state': 'draft' } invoice_idr = inv_obj.create(cr, uid, vals_invoice, context=context) band1 = 1 #Creo detalle Factura if invoice_idr: vals_det_invoice = { 'name': inv_rec.get('name'), 'invoice_id': invoice_idr, 'company_id': inv_rec.get('company_id'), 'partner_id': inv_rec.get('partner_id'), 'product_id': inv_rec.get('product_id'), 'quantity': inv_rec.get('quantity'), 'account_id': inv_rec.get('account_line_id'), 'price_unit': inv_rec.get('price_unit'), 'price_subtotal': inv_rec.get('price_subtotal'), 'origin': inv_rec.get('origin'), } invoice_line_id = inv_line_obj.create( cr, uid, vals_det_invoice) return True def new_ingreso(self, cr, uid, ids, context=None): lis_rec = [] band = 0 obj_caja = self.browse(cr, uid, ids)[0] stock_ware = self.pool.get('stock.picking.type') picking_obj = self.pool.get('stock.picking') move_obj = self.pool.get('stock.move') cchica_lin_obj = self.pool.get('account.caja.chica.line') cchica_line_ids = cchica_lin_obj.search( cr, uid, [('caja_chica_id', '=', obj_caja.id)]) stat_conc_line_obj = cchica_lin_obj.browse(cr, uid, cchica_line_ids, context=context) band = 0 for det_cc in stat_conc_line_obj: #CONDICION SI ES INVENTARIO PARA PROCESAR print "IS INVENT", det_cc.is_inven print "STATE", det_cc.state if det_cc.is_inven and det_cc.state == 'open': if det_cc.product_id.type in ('product', 'consu'): print "PROCESO INVENTARIO Y CONFIRMO LINEA MARCADA", det_cc.id vals_lcchica = {'state': 'confirm'} cchica_lin_obj.write(cr, uid, det_cc.id, vals_lcchica) pic_type_id = stock_ware.search( cr, uid, [('code', '=', 'incoming'), ('warehouse_id.company_id', '=', det_cc.user_id.company_id.id), ('name', '=', 'Recepciones')]) print "ID PIC TYPE", pic_type_id if not pic_type_id: raise osv.except_osv( _('Advertencia!'), _('Primero debe crear un tipo de albarran recepción para la compania de la operación!' )) pic_type_obj = stock_ware.browse(cr, uid, pic_type_id, context=context) for sw in pic_type_obj: id_pt = sw.id wareh_id = sw.warehouse_id.id ub_origen = sw.default_location_src_id.id ub_destino = sw.default_location_dest_id.id if band == 0: picking_vals = { 'picking_type_id': id_pt, 'partner_id': det_cc.partner_id.id, 'date': time.strftime('%Y-%m-%d %H:%M:%S'), 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S') or '' } picking_id = picking_obj.create(cr, uid, picking_vals, context=context) band = 1 if picking_id: vals_stock_move = { 'name': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S') or '', 'product_id': det_cc.product_id.id, 'product_uom': det_cc.product_id.uom_id.id, 'product_uos': det_cc.product_id.uos_id.id, 'date': time.strftime('%Y-%m-%d %H:%M:%S'), 'date_expected': time.strftime('%Y-%m-%d %H:%M:%S'), 'location_id': ub_origen, 'location_dest_id': ub_destino, 'picking_id': picking_id, 'partner_id': det_cc.partner_id.id, 'move_dest_id': False, 'state': 'draft', #'purchase_line_id': order_line.id, 'company_id': det_cc.user_id.company_id.id, 'product_uom_qty': det_cc.cantidad, 'price_unit': round(det_cc.amount_neto / det_cc.cantidad, 2), 'picking_type_id': id_pt, #'group_id': group_id, 'procurement_id': False, 'origin': 'CCHICA' + '-' + time.strftime('%Y-%m-%d %H:%M:%S'), #'route_ids': order.picking_type_id.warehouse_id and [(6, 0, [x.id for x in order.picking_type_id.warehouse_id.route_ids])] or [], 'warehouse_id': wareh_id, 'invoice_state': '2binvoiced', } stock_move_id = move_obj.create( cr, uid, vals_stock_move) else: raise osv.except_osv( _('Advertencia!'), _('No puede crear albarran de un producto que no es de stock!' )) # else: # raise osv.except_osv(_('Advertencia!'), _('Ya no hay mas lineas marcadas para procesar albarranes de ingreso!')) return True def button_dummy(self, cr, uid, ids, context=None): print "IDS***", ids conci_obj = self.pool.get('account.caja.chica') conci_lin_obj = self.pool.get('account.caja.chica.line') stat_conc_line_ids = conci_lin_obj.search( cr, uid, [('caja_chica_id', '=', ids)]) stat_conc_line_obj = conci_lin_obj.browse(cr, uid, stat_conc_line_ids, context=context) valor_bruto = 0.00 valor_neto = 0.00 valor_iva = 0.00 valor_brutof = 0.00 valor_netof = 0.00 valor_ivaf = 0.00 for cc in self.browse(cr, uid, ids, context=context): sal_ini = cc.saldo_ini print "SAL INI", sal_ini for st_lin in stat_conc_line_obj: valor_bruto += round(st_lin.amount, 2) valor_neto += round(st_lin.amount_neto, 2) valor_iva += round(st_lin.amount_iva_retenido, 2) if st_lin.iva_fact: valor_brutof += round(st_lin.amount, 2) valor_netof += round(st_lin.amount_neto, 2) valor_ivaf += round(st_lin.amount_iva_retenido, 2) vals_stat = { 'valor_bruto': valor_bruto, 'saldo_pend': sal_ini - valor_bruto, 'valor_neto': valor_neto, 'valor_iva': valor_iva, 'valor_bruto_f': valor_brutof, 'valor_neto_f': valor_netof, 'valor_iva_f': valor_ivaf } conci_obj.write(cr, uid, ids, vals_stat) return self.write(cr, uid, ids, {'state': 'open'}, context=context) def button_cancel(self, cr, uid, ids, context=None): bnk_st_line_ids = [] #CSV 13-06-2017 Comento para cancelar caja chica no manejo asientos # for st in self.browse(cr, uid, ids, context=context): # bnk_st_line_ids += [line.id for line in st.line_ids] # self.pool.get('account.caja.chica.line').cancel(cr, uid, bnk_st_line_ids, context=context) return self.write(cr, uid, ids, {'state': 'open'}, context=context) def abrir_caja(self, cr, uid, ids, context=None): print "abrir_caja: ", ids self.write(cr, uid, ids, { 'state': 'open', 'date': time.strftime('%Y-%m-%d %H:%M:%S') }) return True
class account_caja_chica_line(osv.osv): def cancel(self, cr, uid, ids, context=None): account_move_obj = self.pool.get('account.move') move_ids = [] for line in self.browse(cr, uid, ids, context=context): if line.journal_entry_id: move_ids.append(line.journal_entry_id.id) for aml in line.journal_entry_id.line_id: if aml.reconcile_id: move_lines = [l.id for l in aml.reconcile_id.line_id] move_lines.remove(aml.id) self.pool.get('account.move.reconcile').unlink( cr, uid, [aml.reconcile_id.id], context=context) if len(move_lines) >= 2: self.pool.get( 'account.move.line').reconcile_partial( cr, uid, move_lines, 'auto', context=context) if move_ids: account_move_obj.button_cancel(cr, uid, move_ids, context=context) account_move_obj.unlink(cr, uid, move_ids, context) _order = "caja_chica_id desc" _name = "account.caja.chica.line" _description = "Caja Chica Detalle" # _inherit = ['ir.needaction_mixin'] _columns = { 'name': fields.char('Concepto', required=True), 'date': fields.date('Fecha', required=True), 'partner_id': fields.many2one('res.partner', 'Proveedor'), 'product_id': fields.many2one('product.product', 'Producto'), 'cantidad': fields.float('Cantidad', select=True, help="Cantidad requerida.", digits_compute=dp.get_precision('Account')), 'amount': fields.float('Total', digits_compute=dp.get_precision('Account')), 'caja_chica_id': fields.many2one('account.caja.chica', 'Caja Chica', select=True, required=True, ondelete='restrict'), 'amount_iva_retenido': fields.float( 'Iva', help= "The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')), 'amount_neto': fields.float( 'Subtotal', help= "The amount expressed in an optional other currency if it is a multi-currency entry.", digits_compute=dp.get_precision('Account')), 'is_inven': fields.boolean( 'Inventario', help="Marcar si es un registro que necesitamos afecte inventarios" ), 'is_iva': fields.boolean('IVA', help="Marcar si es un registro que aplica iva"), 'iva_fact': fields.boolean( 'I.F', help= "Marcar si quiere verificar el valor total del iva de la factura saldra en la parte inferior" ), 'user_id': fields.many2one('res.users', 'Responsable', required=False), 'company_id': fields.related('caja_chica_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), #'partner_name': fields.char('Proveedor Nombre', help="Este campo es usado en el caso que no exista el proveedor requerido para que contabilidad lo cree"), #'note': fields.text('Notes'), 'sequence': fields.integer( 'Sequence', select=True, help= "Gives the sequence order when displaying a list of caja chica."), 'number_fact': fields.char('Factura', size=9, required=True), 'tipo_comp': fields.selection( [('factura', 'Factura'), ('recibo', 'Recibo'), ('nventa', 'N. Venta')], 'Documento', required=True, copy=False, help='Seleccione el tipo de documento que esta registrando.'), 'state': fields.selection( [ ('open', 'Open'), # CSV:2016-04-21 used by cash statements ('confirm', 'Closed') ], 'Status', required=True, readonly="1", copy=False, help='When new statement is created the status will be \'Draft\'.\n' 'And after getting confirmation from the bank it will be in \'Confirmed\' status.' ), 'por_iva': fields.selection([('10', '10%'), ('12', '12%'), ('14', '14%')], '%IVA', required=True, copy=False, help='Seleccione el % de iva de la factura.'), } _defaults = { #'name': lambda self,cr,uid,context={}: self.pool.get('ir.sequence').get(cr, uid, 'account.caja.chica.line'), 'date': lambda self, cr, uid, context={}: context.get( 'date', fields.date.context_today(self, cr, uid, context=context)), 'user_id': lambda obj, cr, uid, context: uid, 'state': 'open', 'por_iva': '12', } def onchange_is_factura(self, cr, uid, ids, tipo_comp, context=None): result = {} print "TIPO Comp", tipo_comp if tipo_comp == 'factura': result = {'value': {'is_iva': True}} else: result = {'value': {'is_iva': False}} return result def onchange_valor_iva(self, cr, uid, ids, tipo_comp, is_iva, amount_neto, por_iva, context=None): result = {} print "TIPO COMP", tipo_comp print "IS IVA", is_iva print "SUBTOTAL", amount_neto iva = int(por_iva) if tipo_comp == 'factura' and is_iva: result = { 'value': { 'amount_iva_retenido': round((amount_neto * iva) / 100, 2), 'amount': round(amount_neto + ((amount_neto * iva) / 100), 2) } } elif tipo_comp == 'factura' and not is_iva: result = { 'value': { 'amount_iva_retenido': 0.00, 'amount': round(amount_neto, 2) } } else: result = { 'value': { 'amount_iva_retenido': 0.00, 'amount': round(amount_neto, 2) } } return result def onchange_is_iva(self, cr, uid, ids, tipo_comp, is_iva, amount_neto, por_iva, context=None): result = {} print "TIPO COMP", tipo_comp print "IS IVA", is_iva print "SUBTOTAL", amount_neto iva = int(por_iva) if tipo_comp == 'factura' and is_iva: result = { 'value': { 'amount_iva_retenido': round((amount_neto * iva) / 100, 2), 'amount': round(amount_neto + ((amount_neto * iva) / 100), 2) } } elif tipo_comp == 'factura' and not is_iva: result = { 'value': { 'amount_iva_retenido': 0.00, 'amount': round(amount_neto, 2) } } else: result = { 'value': { 'amount_iva_retenido': 0.00, 'amount': round(amount_neto, 2) } } return result def onchange_valor_proc(self, cr, uid, ids, tipo_comp, amount, context=None): result = {} print "amount", amount amount_conc = amount print "amount_conc", amount_conc if tipo_comp != 'factura': result = { 'value': { 'amount_iva_retenido': 0.00, 'amount_neto': round(amount, 2) } } else: result = { 'value': { 'amount_iva_retenido': round((amount * 14) / 100, 2), 'amount_neto': round(amount - ((amount * 14) / 100), 2) } } return result
'price': price, 'available': available } return res _columns = { 'name': fields.char('Delivery Method', required=True, translate=True), 'sequence': fields.integer('Sequence', help="Determine the display order"), 'partner_id': fields.many2one('res.partner', 'Transport Company', required=True, help="The partner that is doing the delivery service."), 'product_id': fields.many2one('product.product', 'Delivery Product', required=True), 'grids_id': fields.one2many('delivery.grid', 'carrier_id', 'Delivery Grids'), 'available' : fields.function(get_price, string='Available',type='boolean', multi='price', help="Is the carrier method possible with the current order."), 'price' : fields.function(get_price, string='Price', multi='price'), 'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it."), 'normal_price': fields.float('Normal Price', help="Keep empty if the pricing depends on the advanced pricing per destination"), 'free_if_more_than': fields.boolean('Free If Order Total Amount Is More Than', help="If the order is more expensive than a certain amount, the customer can benefit from a free shipping"), 'amount': fields.float('Amount', help="Amount of the order to benefit from a free shipping, expressed in the company currency"), 'use_detailed_pricelist': fields.boolean('Advanced Pricing per Destination', help="Check this box if you want to manage delivery prices that depends on the destination, the weight, the total of the order, etc."), 'pricelist_ids': fields.one2many('delivery.grid', 'carrier_id', 'Advanced Pricing'), } _defaults = { 'active': 1, 'free_if_more_than': False, 'sequence': 10, } def grid_get(self, cr, uid, ids, contact_id, context=None): contact = self.pool.get('res.partner').browse(cr, uid, contact_id, context=context) for carrier in self.browse(cr, uid, ids, context=context):
def _get_uom_id(self, cr, uid, context=None): try: proxy = self.pool.get('ir.model.data') result = proxy.get_object_reference(cr, uid, 'product', 'product_uom_unit') return result[1] except Exception, ex: return False _columns = { # 'location_destination_id': fields.many2one('stock.location', 'Stock Destination Location'), # 'location_id': fields.many2one('stock.location', 'Stock Source Location'), 'product_id': fields.many2one('product.product', 'Product'), 'back_order_id': fields.many2one('back.to.back.order', 'Back Order'), 'qty': fields.float('Quantity'), 'price': fields.float('Unit Price'), 'subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), 'taxes_id': fields.many2many('account.tax', 'purchase_order_taxe', 'ord_id', 'tax_id', 'Taxes'), 'product_uom': fields.many2one('product.uom', 'Product Unit of Measure', required=True), } _defaults = { 'product_uom' : _get_uom_id, } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: