I tried, same happened. it's related to how Postgres works internally with 
the Django-ORM.

On Wednesday, August 21, 2019 at 3:07:47 PM UTC+2, mohamed habib wrote:
>
> Wild guess in the dark here, as I am unfamiliar with this API. you are 
> doing:
>
>  `payment.pay_request()` 
>
> before creating the WeacceptTransaction object. 
>
> Maybe this line needs to move below: 
> `models.WeAcceptTransaction.objects.create(...)` ? 
>
> At what point is the callback request triggered ?
>
> On Wed, Aug 21, 2019 at 3:36 PM Ahmed Shahwan <a...@shahwan.me 
> <javascript:>> wrote:
>
>> Transaction model:
>>
>>
>> class WeacceptTransaction(Transaction):
>>    """Weaccept's Transaction model"""
>>
>>     # before frontend interaction
>>    auth_token = models.TextField()  # got from step 1
>>    order_id = models.IntegerField(verbose_name="Accept's Order ID")  # 
>> id from step 2
>>    order_url = models.CharField(max_length=255, null=True)  # order_url 
>> from step 2
>>    billing_data = JSONField()  # provided in request for paymet key, 
>> step 3
>>    payment_key = models.TextField()  # payment_token from step 3
>>    hmac = models.TextField(null=True)
>>    # after (from callback)
>>    success_status = models.BooleanField(default=False)
>>    is_refunded = models.BooleanField(default=False)
>>    reference_number = models.IntegerField(null=True)
>>    processed_clbk_json = JSONField(null=True)
>>
>>
>> The cash_payment View:
>>
>> class CashPayment(APIView):
>>    """Cash Payment endpoint"""
>>
>>     serializer_class = serializers.CardPaymentSerializer
>>    required_fields = ["amount_cents", "billing_data"]
>>
>>     def post(self, request):
>>        # Validate required fields
>>        utils.validate(self.required_fields, request)
>>        payment = utils.CashPayment(**request.data)
>>        payment.prepare()
>>        payment.pay_request()
>>        # create a new transaction
>>        models.WeacceptTransaction.objects.create(
>>            merchant_order_id=payment.merchant_order_id,
>>            amount=payment.amount_cents,
>>            auth_token=payment.auth_res.get("token"),
>>            order_id=payment.order_reg_res.get("id"),
>>            order_url=payment.order_reg_res.get("order_url"),
>>            billing_data=payment.billing_data,
>>            payment_key=payment.payment_key_res.get("token"),
>>            hmac=payment.pay_req_res.get("hmac"),
>>        )
>>
>>         return Response(
>>            {
>>                "message": "Our representative will go to the address you 
>> provided "
>>                "to collect the cash from you",
>>                **payment.pay_req_res,
>>            }
>>        )
>>
>>
>> Please note: the first 3 steps are wrapped into the method `prepare()`
>> the 4th step is `pay_request()`
>>
>>
>> the callback-url endpoint (where the 5th step happens) 
>>
>> class TransactionProcessedCallback(APIView):
>>    """Processed callback that will recieve "TRANSACTION", "TOKEN", "ORDER
>> ",
>>       "DELIVERY_STATUS" objects"""
>>
>>     def post(self, request):
>>        # XXX extend to handle TOKEN, DELIVERY_STATUS objects... later
>>        t_obj = request.data.get("obj")  # transaction object
>>        incoming_hmac = request.query_params.get("hmac")
>>        calculated_hmac = utils.calculate_hmac_transaction(t_obj)
>>
>>         # if not equal hmac, not coming from Accept!
>>        if incoming_hmac != calculated_hmac:
>>            return Response(
>>                {"message": "invalid data"}, status=status.
>> HTTP_400_BAD_REQUEST
>>            )
>>
>>         import ipdb
>>
>>         ipdb.set_trace()
>>         # XXX: The error happens here
>>         transaction = models.WeacceptTransaction.objects.get(
>>            merchant_order_id=t_obj.get("order").get("merchant_order_id")
>>        )
>>        transaction.success_status = bool(t_obj.get("success"))
>>        transaction.is_refunded = bool(t_obj.get("is_refunded"))
>>        transaction.reference_number = int(t_obj.get("data").get(
>> "transaction_no") or 1)
>>        transaction.processed_clbk_json = t_obj
>>        transaction.save(
>>            update_fields=[
>>                "success_status",
>>                "is_refunded",
>>                "reference_number",
>>                "processed_clbk_json",
>>            ]
>>        )
>>
>>         email = t_obj.get("order").get("shipping_data").get("email")
>>        # TODO: send mail based upon success status
>>        try:
>>            send_mail(
>>                "Transaction Processed",
>>                "Your transaction is processed",
>>                "SERNDER MAIL",
>>                [email],
>>                fail_silently=False,
>>            )
>>        except Exception as ex:
>>            print(">>>>>>>>>>FAILED TO SEND MAIL")
>>            print(ex)
>>
>>         return Response({"message": "Transaction Updated!"}, status=
>> status.HTTP_200_OK)
>>
>>
>> The 6th step (redirect-url) is irrelevant here, and not included in the 
>> XPAY's service for this payment option.
>>
>>
>> On Wednesday, August 21, 2019 at 2:03:20 PM UTC+2, mohammed habib wrote:
>>>
>>> Are you sure the callback request passes the right parameters ?
>>>
>>> Could you share some of your views code from the 6 steps, and your 
>>> Transaction model ?
>>>
>>> Sent from my iPhone
>>>
>>> On 21 Aug 2019, at 14:46, Ahmed Shahwan <a...@shahwan.me> wrote:
>>>
>>> Hi,
>>>
>>> I have a very strange problem that I don't know why it happens.
>>> I'm creating a REST API service that wraps another REST API payment 
>>> service, let's call the other services XPAY. It has various payment options 
>>> (Card, eWallet, Kiosk, and Cash). The steps required to use the services 
>>> (to make a transaction)
>>>
>>> 1. authentication 2. order registration 3. payment key 4. prepare 
>>> frontend based on payment type 5. Callback URL 6. Redirect URL
>>>
>>> and each step depends on its predecessor. The first 4 steps are 
>>> performed through HTTP Requests that I issue from my service. I store some 
>>> of the information I receive in those steps in a Model called Transaction. 
>>> 5th and 6th steps are Callback endpoints that I create to receive further 
>>> information about the status of the transaction that I started in the first 
>>> 4 steps.
>>>
>>> My endpoints design is:
>>>
>>> myservice/payment/card
>>> myservice/payment/wallet
>>> myservice/payment/kiosk
>>> myservice/payment/cash
>>>
>>> myservice/payment/callback-url
>>> myservice/payment/redirect-url
>>>
>>> These endpoints are wrappers for the payment methods available in XPAY's 
>>> service that my frontend apps will use to provide those payment options for 
>>> users.
>>>
>>> I implemented the first 3 endpoints with no problem. inside those 
>>> endpoints, I create a transaction object with a unique id and then update 
>>> it from inside the *callback-url endpoint* after I receive the 
>>> information from XPAY's service. Note that it takes some time between 
>>> creating the Transaction object and saving it into the database from inside 
>>> my endpoint, and updating it from inside the callback url endpoint.
>>>
>>> The weird thing happens in the 4th endpoint `cash` endpoint. XPAY's 
>>> service responds very quickly on my *callback-url endpoint* and when it 
>>> gets to the updating step, I get *Transaction.DoesNotExist *Exception while 
>>> getting the transaction object using Transaction.objects.get(id=id).
>>>
>>> After some debugging time using ipdb I found that the instance has 
>>> already been saved to the database! and I can retrieve it with its id. but 
>>> when I let it run ordinarily the saving operation doesn't finish until that 
>>> time (I got to know that using some print() statements), which is very 
>>> strange, it's impossible that my laptop is that slow! 
>>>
>>> Solutions I tried:
>>> 1. atomic transaction
>>> 2. time.sleep some time after making the request and saving the 
>>> transaction object to the db
>>> 3. time.sleep in the callback-url before getting the transaction from DB
>>>
>>> I checked any possible logic error related to it and there's nothing 
>>> illogical.
>>>
>>> the issue is related to Postgres and how it operates, and also with 
>>> Django's ORM. I don't know.
>>>
>>> Main technologies I use:
>>> Django 2.2
>>> Postgres Docker container
>>> DRF
>>>
>>> I hope someone gives me an insight into why this is happening and how to 
>>> work around it.
>>>
>>> Thanks
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "Django users" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to django...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/django-users/e43be322-bab9-4162-9fbc-05c6c9b95c94%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/django-users/e43be322-bab9-4162-9fbc-05c6c9b95c94%40googlegroups.com?utm_medium=email&utm_source=footer>
>>> .
>>>
>>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Django users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to django...@googlegroups.com <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-users/a379e013-a01c-4c58-bf2b-0b4cd01f0fae%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/django-users/a379e013-a01c-4c58-bf2b-0b4cd01f0fae%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>
>
> -- 
> Best regards,
> *Mohammed M. Habib, PhD*
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/987c6ce7-70b6-49a9-ab3e-506e369d060e%40googlegroups.com.

Reply via email to