def adyen_form_generate_values(self, cr, uid, id, values, context=None): base_url = self.pool['ir.config_parameter'].get_param( cr, uid, 'web.base.url') acquirer = self.browse(cr, uid, id, context=context) # tmp import datetime from dateutil import relativedelta tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date, 'skinCode': acquirer.adyen_skin_code, 'merchantAccount': acquirer.adyen_merchant_account, 'shopperLocale': values.get('partner_lang'), 'sessionValidity': tmp_date, 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url') else False, 'merchantSig': self._adyen_generate_merchant_sig(acquirer, 'in', values), }) return values
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)['value']) # 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('partner_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)) # Default value of reference is tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context) if not values.get('reference'): self.write(cr, uid, [tx_id], {'reference': str(tx_id)}, context=context) return tx_id
def write(self, cr, uid, ids, values, context=None): Acquirer = self.pool['payment.acquirer'] if ('acquirer_id' in values or 'amount' in values) and 'fees' not in values: # The acquirer or the amount has changed, and the fees are not explicitely forced. Fees must be recomputed. if isinstance(ids, (int, long)): ids = [ids] for txn_id in ids: vals = dict(values) vals['fees'] = 0.0 transaction = self.browse(cr, uid, txn_id, context=context) if 'acquirer_id' in values: acquirer = Acquirer.browse(cr, uid, values['acquirer_id'], context=context) if values['acquirer_id'] else None else: acquirer = transaction.acquirer_id if acquirer: custom_method_name = '%s_compute_fees' % acquirer.provider if hasattr(Acquirer, custom_method_name): amount = (values['amount'] if 'amount' in values else transaction.amount) or 0.0 currency_id = values.get('currency_id') or transaction.currency_id.id country_id = values.get('partner_country_id') or transaction.partner_country_id.id fees = getattr(Acquirer, custom_method_name)(cr, uid, acquirer.id, amount, currency_id, country_id, context=None) vals['fees'] = float_round(fees, 2) res = super(PaymentTransaction, self).write(cr, uid, txn_id, vals, context=context) return res return super(PaymentTransaction, self).write(cr, uid, ids, values, context=context)
def ogone_form_generate_values(self, cr, uid, id, values, context=None): base_url = self.pool['ir.config_parameter'].get_param( cr, uid, 'web.base.url') acquirer = self.browse(cr, uid, id, context=context) ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': acquirer.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', 'LANGUAGE': values.get('partner_lang'), 'CN': values.get('partner_name'), 'EMAIL': values.get('partner_email'), 'OWNERZIP': values.get('partner_zip'), 'OWNERADDRESS': values.get('partner_address'), 'OWNERTOWN': values.get('partner_city'), 'OWNERCTY': values.get('partner_country') and values.get('partner_country').code or '', 'OWNERTELNO': values.get('partner_phone'), 'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneController._accept_url), 'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneController._decline_url), 'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url), 'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url), 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop('return_url') if ogone_tx_values.get('return_url') else False, } if values.get('type') == 'form_save': temp_ogone_tx_values.update({ 'ALIAS': 'YuanCloud-NEW-ALIAS-%s' % time.time(), # something unique, 'ALIASUSAGE': values.get('alias_usage') or acquirer.ogone_alias_usage, }) shasign = self._ogone_generate_shasign(acquirer, 'in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def render(self, cr, uid, id, reference, amount, currency_id, partner_id=False, values=None, context=None): """ Renders the form template of the given acquirer as a qWeb template. :param string reference: the transaction reference :param float amount: the amount the buyer has to pay :param currency_id: currency id :param dict partner_id: optional partner_id to fill values :param dict values: a dictionary of values for the transction that is given to the acquirer-specific method generating the form values :param dict context: YuanCloud context 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_*: partner-related values - partner: optional partner browse record - '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: YuanCloud context dictionary """ if context is None: context = {} if values is None: values = {} acquirer = self.browse(cr, uid, id, context=context) # reference and amount values.setdefault('reference', reference) amount = float_round(amount, 2) values.setdefault('amount', amount) # currency id currency_id = values.setdefault('currency_id', currency_id) 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 values['currency'] = currency # Fill partner_* using values['partner_id'] or partner_id arguement partner_id = values.get('partner_id', partner_id) if partner_id: partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) values.update({ 'partner': partner, 'partner_id': partner_id, 'partner_name': partner.name, 'partner_lang': partner.lang, 'partner_email': partner.email, 'partner_zip': partner.zip, 'partner_city': partner.city, 'partner_address': _partner_format_address(partner.street, partner.street2), 'partner_country_id': partner.country_id.id, 'partner_country': partner.country_id, 'partner_phone': partner.phone, 'partner_state': partner.state_id, }) if values.get('partner_name'): values.update({ 'partner_first_name': _partner_split_name(values.get('partner_name'))[0], 'partner_last_name': _partner_split_name(values.get('partner_name'))[1], }) # Fix address, country fields if not values.get('partner_address'): values['address'] = _partner_format_address(values.get('partner_street', ''), values.get('partner_street2', '')) if not values.get('partner_country') and values.get('partner_country_id'): values['country'] = self.pool['res.country'].browse(cr, uid, values.get('partner_country_id'), context=context) # 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, values['amount'], values['currency_id'], values['partner_country_id'], context=None) values['fees'] = float_round(fees, 2) # 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) values = method(cr, uid, id, values, context=context) values.update({ '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), 'context': context, 'type': values.get('type') or 'form', }) values.setdefault('return_url', False) # 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, values, engine='ir.qweb', context=context)
def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None): ''' Create procurement based on Orderpoint :param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement. This is appropriate for batch jobs only. ''' if context is None: context = {} if use_new_cursor: cr = yuancloud.registry(cr.dbname).cursor() orderpoint_obj = self.pool.get('stock.warehouse.orderpoint') procurement_obj = self.pool.get('procurement.order') product_obj = self.pool.get('product.product') dom = company_id and [('company_id', '=', company_id)] or [] orderpoint_ids = orderpoint_obj.search( cr, uid, dom, order="location_id, purchase_calendar_id, calendar_id") prev_ids = [] tot_procs = [] while orderpoint_ids: ids = orderpoint_ids[:1000] del orderpoint_ids[:1000] dates_dict = {} product_dict = {} ops_dict = {} ops = orderpoint_obj.browse(cr, uid, ids, context=context) #Calculate groups that can be executed together for op in ops: key = (op.location_id.id, op.purchase_calendar_id.id, op.calendar_id.id) res_groups = [] if not dates_dict.get(key): date_groups = self._get_group(cr, uid, op, context=context) for date, group in date_groups: if op.calendar_id and op.calendar_id.attendance_ids: date1, date2 = self._get_next_dates( cr, uid, op, date, group, context=context) res_groups += [ (group, date1, date2, date) ] #date1/date2 as deliveries and date as purchase confirmation date else: res_groups += [(group, date, False, date)] dates_dict[key] = res_groups product_dict[key] = [op.product_id] ops_dict[key] = [op] else: product_dict[key] += [op.product_id] ops_dict[key] += [op] for key in product_dict.keys(): for res_group in dates_dict[key]: ctx = context.copy() ctx.update({'location': ops_dict[key][0].location_id.id}) if res_group[2]: ctx.update({ 'to_date': res_group[2].strftime( DEFAULT_SERVER_DATETIME_FORMAT) }) prod_qty = product_obj._product_available( cr, uid, [x.id for x in product_dict[key]], context=ctx) group = res_group[0] date = res_group[1] subtract_qty = orderpoint_obj.subtract_procurements_from_orderpoints( cr, uid, [x.id for x in ops_dict[key]], context=context) first_op = True ndelivery = date and self._convert_to_UTC( cr, uid, date, context=context) or False npurchase = res_group[3] and self._convert_to_UTC( cr, uid, res_group[3], context=context) or False for op in ops_dict[key]: try: prods = prod_qty[ op.product_id.id]['virtual_available'] if prods is None: continue if float_compare(prods, op.product_min_qty, precision_rounding=op.product_uom. rounding) < 0: qty = max(op.product_min_qty, op.product_max_qty) - prods reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0 if float_compare(reste, 0.0, precision_rounding=op. product_uom.rounding) > 0: qty += op.qty_multiple - reste if float_compare(qty, 0.0, precision_rounding=op. product_uom.rounding) <= 0: continue qty -= subtract_qty[op.id] qty_rounded = float_round( qty, precision_rounding=op.product_uom.rounding) if qty_rounded > 0: proc_id = procurement_obj.create( cr, uid, self._prepare_orderpoint_procurement( cr, uid, op, qty_rounded, date=ndelivery, purchase_date=npurchase, group=group, context=context), context=context) tot_procs.append(proc_id) orderpoint_obj.write( cr, uid, [op.id], { 'last_execution_date': datetime.utcnow().strftime( DEFAULT_SERVER_DATETIME_FORMAT) }, context=context) if use_new_cursor: cr.commit() except OperationalError: if use_new_cursor: orderpoint_ids.append(op.id) cr.rollback() continue else: raise try: tot_procs.reverse() self.run(cr, uid, tot_procs, context=context) tot_procs = [] if use_new_cursor: cr.commit() except OperationalError: if use_new_cursor: cr.rollback() continue else: raise if use_new_cursor: cr.commit() if prev_ids == ids: break else: prev_ids = ids if use_new_cursor: cr.commit() cr.close() return {}
def compute_landed_cost(self, cr, uid, ids, context=None): line_obj = self.pool.get('stock.valuation.adjustment.lines') unlink_ids = line_obj.search(cr, uid, [('cost_id', 'in', ids)], context=context) line_obj.unlink(cr, uid, unlink_ids, context=context) digits = dp.get_precision('Product Price')(cr) towrite_dict = {} for cost in self.browse(cr, uid, ids, context=None): if not cost.picking_ids: continue picking_ids = [p.id for p in cost.picking_ids] total_qty = 0.0 total_cost = 0.0 total_weight = 0.0 total_volume = 0.0 total_line = 0.0 vals = self.get_valuation_lines(cr, uid, [cost.id], picking_ids=picking_ids, context=context) for v in vals: for line in cost.cost_lines: v.update({'cost_id': cost.id, 'cost_line_id': line.id}) self.pool.get('stock.valuation.adjustment.lines').create( cr, uid, v, context=context) total_qty += v.get('quantity', 0.0) total_cost += v.get('former_cost', 0.0) total_weight += v.get('weight', 0.0) total_volume += v.get('volume', 0.0) total_line += 1 for line in cost.cost_lines: value_split = 0.0 for valuation in cost.valuation_adjustment_lines: value = 0.0 if valuation.cost_line_id and valuation.cost_line_id.id == line.id: if line.split_method == 'by_quantity' and total_qty: per_unit = (line.price_unit / total_qty) value = valuation.quantity * per_unit elif line.split_method == 'by_weight' and total_weight: per_unit = (line.price_unit / total_weight) value = valuation.weight * per_unit elif line.split_method == 'by_volume' and total_volume: per_unit = (line.price_unit / total_volume) value = valuation.volume * per_unit elif line.split_method == 'equal': value = (line.price_unit / total_line) elif line.split_method == 'by_current_cost_price' and total_cost: per_unit = (line.price_unit / total_cost) value = valuation.former_cost * per_unit else: value = (line.price_unit / total_line) if digits: value = float_round(value, precision_digits=digits[1], rounding_method='UP') fnc = min if line.price_unit > 0 else max value = fnc(value, line.price_unit - value_split) value_split += value if valuation.id not in towrite_dict: towrite_dict[valuation.id] = value else: towrite_dict[valuation.id] += value if towrite_dict: for key, value in towrite_dict.items(): line_obj.write(cr, uid, key, {'additional_landed_cost': value}, context=context) return True
def _price_rule_get_multi(self, cr, uid, pricelist, products_by_qty_by_partner, context=None): context = context or {} date = context.get('date') and context['date'][0:10] or time.strftime( DEFAULT_SERVER_DATE_FORMAT) products = map(lambda x: x[0], products_by_qty_by_partner) product_uom_obj = self.pool.get('product.uom') if not products: return {} categ_ids = {} for p in products: categ = p.categ_id while categ: categ_ids[categ.id] = True categ = categ.parent_id categ_ids = categ_ids.keys() is_product_template = products[0]._name == "product.template" if is_product_template: prod_tmpl_ids = [tmpl.id for tmpl in products] # all variants of all products prod_ids = [ p.id for p in list( chain.from_iterable( [t.product_variant_ids for t in products])) ] else: prod_ids = [product.id for product in products] prod_tmpl_ids = [ product.product_tmpl_id.id for product in products ] # Load all rules cr.execute( 'SELECT i.id ' 'FROM product_pricelist_item AS i ' 'WHERE (product_tmpl_id IS NULL OR product_tmpl_id = any(%s))' 'AND (product_id IS NULL OR product_id = any(%s))' 'AND (categ_id IS NULL OR categ_id = any(%s)) ' 'AND (pricelist_id = %s) ' 'AND ((i.date_start IS NULL OR i.date_start<=%s) AND (i.date_end IS NULL OR i.date_end>=%s))' 'ORDER BY applied_on, min_quantity desc', (prod_tmpl_ids, prod_ids, categ_ids, pricelist.id, date, date)) item_ids = [x[0] for x in cr.fetchall()] items = self.pool.get('product.pricelist.item').browse(cr, uid, item_ids, context=context) results = {} for product, qty, partner in products_by_qty_by_partner: results[product.id] = 0.0 suitable_rule = False # Final unit price is computed according to `qty` in the `qty_uom_id` UoM. # An intermediary unit price may be computed according to a different UoM, in # which case the price_uom_id contains that UoM. # The final price will be converted to match `qty_uom_id`. qty_uom_id = context.get('uom') or product.uom_id.id price_uom_id = product.uom_id.id qty_in_product_uom = qty if qty_uom_id != product.uom_id.id: try: qty_in_product_uom = product_uom_obj._compute_qty( cr, uid, context['uom'], qty, product.uom_id.id) except UserError: # Ignored - incompatible UoM in context, use default product UoM pass # if Public user try to access standard price from website sale, need to call _price_get. price = self.pool['product.template']._price_get( cr, uid, [product], 'list_price', context=context)[product.id] price_uom_id = qty_uom_id for rule in items: if rule.min_quantity and qty_in_product_uom < rule.min_quantity: continue if is_product_template: if rule.product_tmpl_id and product.id != rule.product_tmpl_id.id: continue if rule.product_id and \ (product.product_variant_count > 1 or product.product_variant_ids[0].id != rule.product_id.id): # product rule acceptable on template if has only one variant continue else: if rule.product_tmpl_id and product.product_tmpl_id.id != rule.product_tmpl_id.id: continue if rule.product_id and product.id != rule.product_id.id: continue if rule.base == 'pricelist' and rule.base_pricelist_id: price_tmp = self._price_get_multi( cr, uid, rule.base_pricelist_id, [(product, qty, partner)], context=context)[product.id] ptype_src = rule.base_pricelist_id.currency_id.id price = self.pool['res.currency'].compute( cr, uid, ptype_src, pricelist.currency_id.id, price_tmp, round=False, context=context) else: # if base option is public price take sale price else cost price of product # price_get returns the price in the context UoM, i.e. qty_uom_id price = self.pool['product.template']._price_get( cr, uid, [product], rule.base, context=context)[product.id] convert_to_price_uom = ( lambda price: product_uom_obj._compute_price( cr, uid, product.uom_id.id, price, price_uom_id)) if price is not False: if rule.compute_price == 'fixed': price = convert_to_price_uom(rule.fixed_price) elif rule.compute_price == 'percentage': price = (price - (price * (rule.percent_price / 100))) or 0.0 else: #complete formula price_limit = price price = (price - (price * (rule.price_discount / 100))) or 0.0 if rule.price_round: price = tools.float_round( price, precision_rounding=rule.price_round) if rule.price_surcharge: price_surcharge = convert_to_price_uom( rule.price_surcharge) price += price_surcharge if rule.price_min_margin: price_min_margin = convert_to_price_uom( rule.price_min_margin) price = max(price, price_limit + price_min_margin) if rule.price_max_margin: price_max_margin = convert_to_price_uom( rule.price_max_margin) price = min(price, price_limit + price_max_margin) suitable_rule = rule break # Final price conversion into pricelist currency if suitable_rule and suitable_rule.compute_price != 'fixed' and suitable_rule.base != 'pricelist': user_company = self.pool['res.users'].browse( cr, uid, uid, context=context).company_id price = self.pool['res.currency'].compute( cr, uid, user_company.currency_id.id, pricelist.currency_id.id, price, context=context) results[product.id] = (price, suitable_rule and suitable_rule.id or False) return results
def _procure_orderpoint_confirm(self, cr, uid, use_new_cursor=False, company_id=False, context=None): ''' Create procurement based on Orderpoint :param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing each procurement. This is appropriate for batch jobs only. ''' if context is None: context = {} if use_new_cursor: cr = yuancloud.registry(cr.dbname).cursor() orderpoint_obj = self.pool.get('stock.warehouse.orderpoint') procurement_obj = self.pool.get('procurement.order') product_obj = self.pool.get('product.product') dom = company_id and [('company_id', '=', company_id)] or [] orderpoint_ids = orderpoint_obj.search(cr, uid, dom, order="location_id") prev_ids = [] tot_procs = [] while orderpoint_ids: ids = orderpoint_ids[:1000] del orderpoint_ids[:1000] product_dict = {} ops_dict = {} ops = orderpoint_obj.browse(cr, uid, ids, context=context) #Calculate groups that can be executed together for op in ops: key = (op.location_id.id,) if not product_dict.get(key): product_dict[key] = [op.product_id] ops_dict[key] = [op] else: product_dict[key] += [op.product_id] ops_dict[key] += [op] for key in product_dict.keys(): ctx = context.copy() ctx.update({'location': ops_dict[key][0].location_id.id}) prod_qty = product_obj._product_available(cr, uid, [x.id for x in product_dict[key]], context=ctx) subtract_qty = orderpoint_obj.subtract_procurements_from_orderpoints(cr, uid, [x.id for x in ops_dict[key]], context=context) for op in ops_dict[key]: try: prods = prod_qty[op.product_id.id]['virtual_available'] if prods is None: continue if float_compare(prods, op.product_min_qty, precision_rounding=op.product_uom.rounding) <= 0: qty = max(op.product_min_qty, op.product_max_qty) - prods reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0 if float_compare(reste, 0.0, precision_rounding=op.product_uom.rounding) > 0: qty += op.qty_multiple - reste if float_compare(qty, 0.0, precision_rounding=op.product_uom.rounding) < 0: continue qty -= subtract_qty[op.id] qty_rounded = float_round(qty, precision_rounding=op.product_uom.rounding) if qty_rounded > 0: proc_id = procurement_obj.create(cr, uid, self._prepare_orderpoint_procurement(cr, uid, op, qty_rounded, context=context), context=context) tot_procs.append(proc_id) if use_new_cursor: cr.commit() except OperationalError: if use_new_cursor: orderpoint_ids.append(op.id) cr.rollback() continue else: raise try: tot_procs.reverse() self.run(cr, uid, tot_procs, context=context) tot_procs = [] if use_new_cursor: cr.commit() except OperationalError: if use_new_cursor: cr.rollback() continue else: raise if use_new_cursor: cr.commit() if prev_ids == ids: break else: prev_ids = ids if use_new_cursor: cr.commit() cr.close() return {}