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 <[email protected] 
> <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 <[email protected]> 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 [email protected].
>>> 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 [email protected] <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 [email protected].
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