def test_cancel_line_item_in_order(self): original_quantity = 2 order_item = Item.query.filter_by(name='t-shirt').first() total_amount = order_item.current_price().amount * original_quantity data = { 'line_items': [{'item_id': unicode(order_item.id), 'quantity': original_quantity}], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_json = json.loads(resp.data)['result'] self.assertEquals(resp_json['final_amount'], total_amount) order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() refund_amount = total_amount - 1 razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data={'id': buid()})) pre_refund_transactions_count = order.refund_transactions.count() formdata = { 'amount': refund_amount, 'internal_note': 'internal reference', 'refund_description': 'receipt description', 'note_to_user': '******' } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST' } with app.request_context(self.post_env): process_partial_refund_for_order(partial_refund_args) self.assertEquals(pre_refund_transactions_count + 1, order.refund_transactions.count()) first_line_item = order.line_items[0] # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data={'id': buid()})) process_line_item_cancellation(first_line_item) self.assertEquals(first_line_item.status, LINE_ITEM_STATUS.CANCELLED) expected_refund_amount = total_amount - refund_amount refund_transaction1 = PaymentTransaction.query.filter_by(order=order, transaction_type=TRANSACTION_TYPE.REFUND).order_by(PaymentTransaction.created_at.desc()).first() self.assertEquals(refund_transaction1.amount, expected_refund_amount)
def partial_refund(**kwargs): """ Processes a partial refund for an order. Params are order_id, amount, internal_note, refund_description, note_to_user """ form_dict = { 'amount': kwargs['amount'], 'internal_note': kwargs['internal_note'], 'refund_description': kwargs['refund_description'], 'note_to_user': kwargs['note_to_user'] } order = Order.query.get(kwargs['order_id']) with app.test_request_context(): process_partial_refund_for_order(order, form_dict)
def partial_refund(**kwargs): """ Processes a partial refund for an order. Params are order_id, amount, internal_note, refund_description, note_to_user """ form_dict = { 'amount': kwargs['amount'], 'internal_note': kwargs['internal_note'], 'refund_description': kwargs['refund_description'], 'note_to_user': kwargs['note_to_user'], } order = Order.query.get(kwargs['order_id']) with app.test_request_context(): process_partial_refund_for_order(order, form_dict)
def test_partial_refund_in_order(self): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price( ).amount * original_quantity data = { 'line_items': [{ 'item_id': unicode(discounted_item.id), 'quantity': original_quantity }], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_data = json.loads(resp.data)['result'] self.assertEquals( resp_data['final_amount'], (total_amount - 5 * total_amount / decimal.Decimal(100))) order = Order.query.get(resp_data['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) valid_refund_amount = 500 valid_refund_dict = { 'amount': valid_refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******', 'refund_description': 'test refund' } process_partial_refund_for_order(order, valid_refund_dict) refund_transactions = order.transactions.filter_by( transaction_type=TRANSACTION_TYPE.REFUND).all() self.assertIsInstance(refund_transactions[0].refunded_at, datetime.datetime) self.assertEquals(refund_transactions[0].amount, decimal.Decimal(valid_refund_amount)) self.assertEquals(refund_transactions[0].internal_note, valid_refund_dict['internal_note']) self.assertEquals(refund_transactions[0].note_to_user, valid_refund_dict['note_to_user']) self.assertEquals(refund_transactions[0].refund_description, valid_refund_dict['refund_description']) invalid_refund_amount = 100000000 invalid_refund_dict = {'amount': invalid_refund_amount} resp = process_partial_refund_for_order(order, invalid_refund_dict) self.assertEquals(resp.status_code, 403) refund_transactions = order.transactions.filter_by( transaction_type=TRANSACTION_TYPE.REFUND).all() self.assertEquals(refund_transactions[0].amount, decimal.Decimal(valid_refund_amount)) resp = self.make_free_order() self.assertEquals(resp.status_code, 201) resp_data = json.loads(resp.data)['result'] order = Order.query.get(resp_data.get('order_id')) invalid_refund_amount = 100000000 invalid_refund_dict = {'amount': invalid_refund_amount} refund_resp = process_partial_refund_for_order(order, invalid_refund_dict) self.assertEquals(refund_resp.status_code, 403)
def test_cancel_line_item_in_bulk_order(self): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price( ).amount * original_quantity data = { 'line_items': [{ 'item_id': unicode(discounted_item.id), 'quantity': original_quantity }], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_json = json.loads(resp.data)['result'] self.assertEquals( resp_json['final_amount'], (total_amount - 5 * total_amount / decimal.Decimal(100))) order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() first_line_item = order.line_items[0] to_be_void_line_items = order.line_items[1:] precancellation_order_amount = order.net_amount # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) process_line_item_cancellation(first_line_item) self.assertEquals(first_line_item.status, LINE_ITEM_STATUS.CANCELLED) for void_line_item in to_be_void_line_items: self.assertEquals(void_line_item.status, LINE_ITEM_STATUS.VOID) expected_refund_amount = precancellation_order_amount - order.get_amounts( LINE_ITEM_STATUS.CONFIRMED).final_amount refund_transaction1 = PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND).first() self.assertEquals(refund_transaction1.amount, expected_refund_amount) second_line_item = order.get_confirmed_line_items[0] razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) process_line_item_cancellation(second_line_item) self.assertEquals(second_line_item.status, LINE_ITEM_STATUS.CANCELLED) refund_transaction2 = PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND).order_by( 'created_at desc').first() self.assertEquals(refund_transaction2.amount, second_line_item.final_amount) # test failed cancellation third_line_item = order.get_confirmed_line_items[0] failed_response = make_response('', 400) failed_response.content = 'failed' razorpay.refund_payment = MagicMock(return_value=failed_response) self.assertRaises( PaymentGatewayError, lambda: process_line_item_cancellation(third_line_item)) # refund the remaining amount paid, and attempt to cancel a line item # this should cancel the line item without resulting in a new refund transaction refund_amount = order.net_amount refund_dict = { 'amount': refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******' } razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) process_partial_refund_for_order(order, refund_dict) third_line_item = order.get_confirmed_line_items[0] pre_cancellation_transactions_count = order.refund_transactions.count() cancelled_refund_amount = process_line_item_cancellation( third_line_item) self.assertEquals(cancelled_refund_amount, decimal.Decimal(0)) self.assertEquals(pre_cancellation_transactions_count, order.refund_transactions.count()) # test free line item cancellation free_order_resp = self.make_free_order() free_order_resp_data = json.loads(free_order_resp.data)['result'] free_order = Order.query.get(free_order_resp_data.get('order_id')) free_line_item = free_order.line_items[0] process_line_item_cancellation(free_line_item) self.assertEquals(free_line_item.status, LINE_ITEM_STATUS.CANCELLED) self.assertEquals(free_order.transactions.count(), 0)
def test_cancel_line_item_in_order(self): original_quantity = 2 order_item = Item.query.filter_by(name='t-shirt').first() total_amount = order_item.current_price().amount * original_quantity data = { 'line_items': [{ 'item_id': unicode(order_item.id), 'quantity': original_quantity }], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_json = json.loads(resp.data)['result'] self.assertEquals(resp_json['final_amount'], total_amount) order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() refund_amount = total_amount - 1 refund_dict = { 'amount': refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******' } razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) pre_refund_transactions_count = order.refund_transactions.count() process_partial_refund_for_order(order, refund_dict) self.assertEquals(pre_refund_transactions_count + 1, order.refund_transactions.count()) first_line_item = order.line_items[0] # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse( response_data={'id': buid()})) process_line_item_cancellation(first_line_item) self.assertEquals(first_line_item.status, LINE_ITEM_STATUS.CANCELLED) expected_refund_amount = total_amount - refund_amount refund_transaction1 = PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND).order_by( 'created_at desc').first() self.assertEquals(refund_transaction1.amount, expected_refund_amount)
def test_partial_refund_in_order(self): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price().amount * original_quantity data = { 'line_items': [{'item_id': unicode(discounted_item.id), 'quantity': original_quantity}], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_data = json.loads(resp.data)['result'] self.assertEquals(resp_data['final_amount'], (total_amount - 5 * total_amount / decimal.Decimal(100))) order = Order.query.get(resp_data['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data={'id': buid()})) valid_refund_amount = 500 formdata = { 'amount': valid_refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******', 'refund_description': 'test refund' } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST' } with app.request_context(self.post_env): process_partial_refund_for_order(partial_refund_args) refund_transactions = order.transactions.filter_by(transaction_type=TRANSACTION_TYPE.REFUND).all() self.assertIsInstance(refund_transactions[0].refunded_at, datetime.datetime) self.assertEquals(refund_transactions[0].amount, decimal.Decimal(valid_refund_amount)) self.assertEquals(refund_transactions[0].internal_note, formdata['internal_note']) self.assertEquals(refund_transactions[0].note_to_user, formdata['note_to_user']) self.assertEquals(refund_transactions[0].refund_description, formdata['refund_description']) invalid_refund_amount = 100000000 formdata = { 'amount': invalid_refund_amount, } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST' } with app.request_context(self.post_env): resp = process_partial_refund_for_order(partial_refund_args) self.assertEquals(resp.status_code, 403) refund_transactions = order.transactions.filter_by(transaction_type=TRANSACTION_TYPE.REFUND).all() self.assertEquals(refund_transactions[0].amount, decimal.Decimal(valid_refund_amount)) resp = self.make_free_order() self.assertEquals(resp.status_code, 201) resp_data = json.loads(resp.data)['result'] order = Order.query.get(resp_data.get('order_id')) invalid_refund_amount = 100000000 formdata = { 'amount': invalid_refund_amount, } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST' } with app.request_context(self.post_env): refund_resp = process_partial_refund_for_order(partial_refund_args) self.assertEquals(refund_resp.status_code, 403)
def test_cancel_line_item_in_bulk_order(self): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price().amount * original_quantity data = { 'line_items': [{'item_id': unicode(discounted_item.id), 'quantity': original_quantity}], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', } } ic = ItemCollection.query.first() # make a purchase order resp = self.client.post('/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL'])]) self.assertEquals(resp.status_code, 201) resp_json = json.loads(resp.data)['result'] self.assertEquals(resp_json['final_amount'], (total_amount - 5 * total_amount / decimal.Decimal(100))) order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction(order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR) db.session.add(transaction) order.confirm_sale() db.session.commit() first_line_item = order.line_items[0] to_be_void_line_items = order.line_items[1:] precancellation_order_amount = order.net_amount # Mock Razorpay's API razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data={'id': buid()})) process_line_item_cancellation(first_line_item) self.assertEquals(first_line_item.status, LINE_ITEM_STATUS.CANCELLED) for void_line_item in to_be_void_line_items: self.assertEquals(void_line_item.status, LINE_ITEM_STATUS.VOID) expected_refund_amount = precancellation_order_amount - order.get_amounts(LINE_ITEM_STATUS.CONFIRMED).final_amount refund_transaction1 = PaymentTransaction.query.filter_by(order=order, transaction_type=TRANSACTION_TYPE.REFUND).first() self.assertEquals(refund_transaction1.amount, expected_refund_amount) second_line_item = order.confirmed_line_items[0] razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data={'id': buid()})) process_line_item_cancellation(second_line_item) self.assertEquals(second_line_item.status, LINE_ITEM_STATUS.CANCELLED) refund_transaction2 = PaymentTransaction.query.filter_by(order=order, transaction_type=TRANSACTION_TYPE.REFUND).order_by(PaymentTransaction.created_at.desc()).first() self.assertEquals(refund_transaction2.amount, second_line_item.final_amount) # test failed cancellation third_line_item = order.confirmed_line_items[0] razorpay.refund_payment = MagicMock( return_value=MockResponse( response_data={ "error": { "code": "BAD_REQUEST_ERROR", "description": "The amount is invalid", "field": "amount" } }, status_code=400 )) self.assertRaises(PaymentGatewayError, lambda: process_line_item_cancellation(third_line_item)) # refund the remaining amount paid, and attempt to cancel a line item # this should cancel the line item without resulting in a new refund transaction refund_amount = order.net_amount refund_dict = {'id': buid(), 'amount': refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******'} razorpay.refund_payment = MagicMock(return_value=MockResponse(response_data=refund_dict)) formdata = { 'amount': refund_amount, 'internal_note': 'internal reference', 'refund_description': 'receipt description', 'note_to_user': '******' } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST' } with app.request_context(self.post_env): process_partial_refund_for_order(partial_refund_args) third_line_item = order.confirmed_line_items[0] pre_cancellation_transactions_count = order.refund_transactions.count() cancelled_refund_amount = process_line_item_cancellation(third_line_item) self.assertEquals(cancelled_refund_amount, decimal.Decimal(0)) self.assertEquals(pre_cancellation_transactions_count, order.refund_transactions.count()) # test free line item cancellation free_order_resp = self.make_free_order() free_order_resp_data = json.loads(free_order_resp.data)['result'] free_order = Order.query.get(free_order_resp_data.get('order_id')) free_line_item = free_order.line_items[0] process_line_item_cancellation(free_line_item) self.assertEquals(free_line_item.status, LINE_ITEM_STATUS.CANCELLED) self.assertEquals(free_order.transactions.count(), 0)
def test_partial_refund_in_order(db_session, client, all_data, post_env): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price().amount * original_quantity data = { 'line_items': [ {'item_id': str(discounted_item.id), 'quantity': original_quantity} ], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', }, } ic = ItemCollection.query.first() # make a purchase order resp = client.post( '/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[ ('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL']), ], ) assert resp.status_code == 201 resp_data = json.loads(resp.data)['result'] assert resp_data['final_amount'] == ( total_amount - 5 * total_amount / decimal.Decimal(100) ) order = Order.query.get(resp_data['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction( order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR, ) db_session.add(transaction) order.confirm_sale() db_session.commit() # Mock Razorpay's API razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data={'id': buid()}) ) valid_refund_amount = 500 formdata = { 'amount': valid_refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******', 'refund_description': 'test refund', } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST', } with app.request_context(post_env): process_partial_refund_for_order(partial_refund_args) refund_transactions = order.transactions.filter_by( transaction_type=TRANSACTION_TYPE.REFUND ).all() assert isinstance(refund_transactions[0].refunded_at, datetime.datetime) assert refund_transactions[0].amount == decimal.Decimal(valid_refund_amount) assert refund_transactions[0].internal_note == formdata['internal_note'] assert str(refund_transactions[0].note_to_user) == formdata['note_to_user'] assert refund_transactions[0].refund_description == formdata['refund_description'] invalid_refund_amount = 100000000 formdata = { 'amount': invalid_refund_amount, } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST', } with app.request_context(post_env): resp = process_partial_refund_for_order(partial_refund_args) assert resp.status_code == 403 refund_transactions = order.transactions.filter_by( transaction_type=TRANSACTION_TYPE.REFUND ).all() assert refund_transactions[0].amount == decimal.Decimal(valid_refund_amount) resp = make_free_order(client) assert resp.status_code == 201 resp_data = json.loads(resp.data)['result'] order = Order.query.get(resp_data.get('order_id')) invalid_refund_amount = 100000000 formdata = { 'amount': invalid_refund_amount, } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST', } with app.request_context(post_env): refund_resp = process_partial_refund_for_order(partial_refund_args) assert refund_resp.status_code == 403
def test_cancel_line_item_in_bulk_order(db_session, client, all_data, post_env): original_quantity = 5 discounted_item = Item.query.filter_by(name='t-shirt').first() total_amount = discounted_item.current_price().amount * original_quantity data = { 'line_items': [ {'item_id': str(discounted_item.id), 'quantity': original_quantity} ], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', }, } ic = ItemCollection.query.first() # make a purchase order resp = client.post( '/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[ ('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL']), ], ) assert resp.status_code == 201 resp_json = json.loads(resp.data)['result'] assert resp_json['final_amount'] == ( total_amount - 5 * total_amount / decimal.Decimal(100) ) order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction( order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR, ) db_session.add(transaction) order.confirm_sale() db_session.commit() first_line_item = order.line_items[0] to_be_void_line_items = order.line_items[1:] precancellation_order_amount = order.net_amount # Mock Razorpay's API razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data={'id': buid()}) ) process_line_item_cancellation(first_line_item) assert first_line_item.status == LINE_ITEM_STATUS.CANCELLED for void_line_item in to_be_void_line_items: assert void_line_item.status == LINE_ITEM_STATUS.VOID expected_refund_amount = ( precancellation_order_amount - order.get_amounts(LINE_ITEM_STATUS.CONFIRMED).final_amount ) refund_transaction1 = PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND ).first() assert refund_transaction1.amount == expected_refund_amount second_line_item = order.confirmed_line_items[0] razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data={'id': buid()}) ) process_line_item_cancellation(second_line_item) assert second_line_item.status == LINE_ITEM_STATUS.CANCELLED refund_transaction2 = ( PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND ) .order_by(PaymentTransaction.created_at.desc()) .first() ) assert refund_transaction2.amount == second_line_item.final_amount # test failed cancellation third_line_item = order.confirmed_line_items[0] razorpay.refund_payment = MagicMock( return_value=MockResponse( response_data={ 'error': { 'code': 'BAD_REQUEST_ERROR', 'description': "The amount is invalid", 'field': 'amount', } }, status_code=400, ) ) with pytest.raises(PaymentGatewayError): process_line_item_cancellation(third_line_item) # refund the remaining amount paid, and attempt to cancel a line item # this should cancel the line item without resulting in a new refund transaction refund_amount = order.net_amount refund_dict = { 'id': buid(), 'amount': refund_amount, 'internal_note': 'internal reference', 'note_to_user': '******', } razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data=refund_dict) ) formdata = { 'amount': refund_amount, 'internal_note': 'internal reference', 'refund_description': 'receipt description', 'note_to_user': '******', } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST', } with app.request_context(post_env): process_partial_refund_for_order(partial_refund_args) third_line_item = order.confirmed_line_items[0] pre_cancellation_transactions_count = order.refund_transactions.count() cancelled_refund_amount = process_line_item_cancellation(third_line_item) assert cancelled_refund_amount == decimal.Decimal(0) assert pre_cancellation_transactions_count == order.refund_transactions.count() # test free line item cancellation free_order_resp = make_free_order(client) free_order_resp_data = json.loads(free_order_resp.data)['result'] free_order = Order.query.get(free_order_resp_data.get('order_id')) free_line_item = free_order.line_items[0] process_line_item_cancellation(free_line_item) assert free_line_item.status == LINE_ITEM_STATUS.CANCELLED assert free_order.transactions.count() == 0
def test_cancel_line_item_in_order(db_session, client, all_data, post_env): original_quantity = 2 order_item = Item.query.filter_by(name='t-shirt').first() total_amount = order_item.current_price().amount * original_quantity data = { 'line_items': [{'item_id': str(order_item.id), 'quantity': original_quantity}], 'buyer': { 'fullname': 'Testing', 'phone': '9814141414', 'email': '*****@*****.**', }, } ic = ItemCollection.query.first() # make a purchase order resp = client.post( '/ic/{ic}/order'.format(ic=ic.id), data=json.dumps(data), content_type='application/json', headers=[ ('X-Requested-With', 'XMLHttpRequest'), ('Origin', app.config['BASE_URL']), ], ) assert resp.status_code == 201 resp_json = json.loads(resp.data)['result'] assert resp_json['final_amount'] == total_amount order = Order.query.get(resp_json['order_id']) # Create fake payment and transaction objects online_payment = OnlinePayment(pg_paymentid='pg_testpayment', order=order) online_payment.confirm() order_amounts = order.get_amounts(LINE_ITEM_STATUS.PURCHASE_ORDER) transaction = PaymentTransaction( order=order, online_payment=online_payment, amount=order_amounts.final_amount, currency=CURRENCY.INR, ) db_session.add(transaction) order.confirm_sale() db_session.commit() refund_amount = total_amount - 1 razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data={'id': buid()}) ) pre_refund_transactions_count = order.refund_transactions.count() formdata = { 'amount': refund_amount, 'internal_note': 'internal reference', 'refund_description': 'receipt description', 'note_to_user': '******', } refund_form = OrderRefundForm(data=formdata, parent=order, meta={'csrf': False}) partial_refund_args = { 'order': order, 'form': refund_form, 'request_method': 'POST', } with app.request_context(post_env): process_partial_refund_for_order(partial_refund_args) assert pre_refund_transactions_count + 1 == order.refund_transactions.count() first_line_item = order.line_items[0] # Mock Razorpay's API razorpay.refund_payment = MagicMock( return_value=MockResponse(response_data={'id': buid()}) ) process_line_item_cancellation(first_line_item) assert first_line_item.status == LINE_ITEM_STATUS.CANCELLED expected_refund_amount = total_amount - refund_amount refund_transaction1 = ( PaymentTransaction.query.filter_by( order=order, transaction_type=TRANSACTION_TYPE.REFUND ) .order_by(PaymentTransaction.created_at.desc()) .first() ) assert refund_transaction1.amount == expected_refund_amount