Score:2

บันทึกข้อมูลลงในคำสั่งซื้ออย่างปลอดภัยใน onNotify()

ธง jp

ฉันเพิ่งเริ่มใช้ Drupal และต้องสร้างเกตเวย์การชำระเงินนอกสถานที่ (ด้วย Drupal Commerce 2) ทุกอย่างใช้งานได้ แต่บางครั้งก็ไม่ทำงาน

เซิร์ฟเวอร์ของผู้ให้บริการชำระเงินทางไกลส่งคำขอการแจ้งเตือนไปยังเซิร์ฟเวอร์ เกี่ยวกับสถานะของการชำระเงิน ดังนั้นฉันจึงมีทั้งสองอย่าง เมื่อกลับมา และ เมื่อแจ้งเตือน ในคลาส PaymentGateway

เนื่องจาก เมื่อกลับมา ไม่รับประกันว่าจะถูกเรียก (ลูกค้าอาจปิดเบราว์เซอร์ ฯลฯ และผู้ให้บริการไม่จำเป็นต้องส่งเขากลับในกรณีของฉัน) แต่ เมื่อแจ้งเตือน รับประกันว่าจะเรียกฉันสร้างและบันทึก การชำระเงิน คัดค้านใน เมื่อแจ้งเตือน, ไม่เข้า เมื่อกลับมา, เมื่อชำระเงินเรียบร้อยแล้ว. (นี่คือสิ่งที่เอกสารแนะนำให้ทำ: https://docs.drupalcommerce.org/commerce2/developer-guide/payments/create-payment-gateway/off-site-gateways/handling-ipn)

รหัสของฉันจึงมีลักษณะดังนี้ (เป็นรหัสเทียมที่เรียบง่ายมาก ไม่รวมการตรวจสอบความถูกต้อง)

คลาส RedirectCheckout ขยาย OffsitePaymentGatewayBase ใช้ SupportsNotificationsInterface {

  ฟังก์ชั่นสาธารณะ onReturn () {
    $is_order_accepted = /* ตรวจสอบว่าผู้ให้บริการชำระเงินทางไกลยอมรับคำสั่งซื้อแล้ว */
    ถ้า (!$is_order_accepted) {
       โยน NeedsRedirectException ใหม่ ()
    }
    // ถ้าทุกอย่างดีแล้ว ไม่ต้องทำอะไร
  }

  ฟังก์ชั่นสาธารณะ onNotify () {
    /** @var OrderInterface $คำสั่ง */
    $order = /* โหลดคำสั่งซื้อที่มีการแจ้งเตือน */

    $is_order_accepted = /* ตรวจสอบว่าผู้ให้บริการชำระเงินทางไกลยอมรับคำสั่งซื้อแล้ว */
    ถ้า ($is_order_accepted) {
      $payment = $payment_storage->สร้าง ();
      $payment->save();
      $order->setData('transaction_id', $transactionId);
      $order->save(); // นี่คือสิ่งที่บางครั้งเขียนทับโดย onReturn() ฉันเชื่อ
    }
  }
}

โปรดทราบว่าฉันจำเป็นต้องบันทึกข้อมูลบางอย่างในคำสั่งซื้อ เมื่อคำสั่งซื้อได้รับการยอมรับ (ซึ่งไม่สามารถใช้งานได้เมื่อสร้างคำสั่งซื้อ เฉพาะเมื่อชำระเงินสำเร็จแล้วเท่านั้น)
เอกสารประกอบของ Drupal Commerce ระบุว่าคุณ "ไม่จำเป็น (และไม่ควร)" แตะที่คำสั่งซื้อ แต่ฉันต้องบันทึกข้อมูลเพิ่มเติมเกี่ยวกับคำสั่งซื้อที่ส่วนอื่นๆ ในระบบคาดว่าจะมีอยู่

สิ่งนี้มักจะได้ผล อย่างไรก็ตามทั้งสอง เมื่อกลับมา และ เมื่อแจ้งเตือน คำขอจากเซิร์ฟเวอร์ระยะไกลบางครั้งมาถึงในเวลาเดียวกัน ซึ่งฉันเชื่อว่านำไปสู่สภาวะการแย่งชิง

น่าเสียดายที่แม้ว่าฉันจะไม่ได้ทำอะไรตามคำสั่ง เมื่อกลับมาดูเหมือนว่าการค้าจะยังคงบันทึกคำสั่งซื้อ ฉันเชื่อว่าบางครั้งสิ่งนี้สามารถเขียนทับข้อมูลที่บันทึกไว้ในคำสั่งซื้อโดย เมื่อแจ้งเตือน. ตัวอย่างเช่น:

  • เมื่อกลับมา เริ่มทำงานและโหลดคำสั่งซื้อ (ดำเนินการโดยไลบรารีการค้าเอง ดังนั้นฉันจึงไม่สามารถทำอะไรเกี่ยวกับเรื่องนี้ได้)
  • คำขอแจ้งเตือนมาถึงดังนั้น เมื่อแจ้งเตือน เริ่มทำงาน โหลดและบันทึกคำสั่งซื้อ และส่งคืน
  • หลังจากนี้ ผ เมื่อกลับมา เมธอดส่งคืน ให้การควบคุมแก่ Commerce ซึ่งจะบันทึกคำสั่งซื้ออีกครั้ง เนื่องจากโหลดวัตถุคำสั่งซื้อมาก่อน เมื่อแจ้งเตือน บันทึกมันเขียนทับอะไรก็ตาม เมื่อแจ้งเตือน เขียนด้วยข้อมูลเก่า

(บางทีคำสั่งสนทนาอาจเป็นปัญหาได้เช่นกัน โดยที่ เมื่อแจ้งเตือน สามารถเขียนทับข้อมูลใด ๆ ที่บันทึกไว้ในคำสั่งซื้อโดย Drupal Commerce ที่อยู่เบื้องหลัง หากมี ในระหว่าง เมื่อกลับมา ขอ.)

มีวิธีจัดการที่ดีหรือไม่ เช่น หลีกเลี่ยงสภาพการแข่งขันเพื่อให้สามารถบันทึกข้อมูลการสั่งซื้อได้ เมื่อแจ้งเตือน?

ฉันใช้ Drupal 8.6

Gabriel Fernandez avatar
cn flag
คุณเคยลองใช้เหตุการณ์ เช่น `commerce_order.place.post_transition` หรือไม่
jp flag
แนวคิดที่น่าสนใจ - ฉันจะพิจารณาว่ามันทำงานอย่างไร
jp flag
Good suggestion! Unfortunately, according to my tests, onNotify() doesn't place the order by itself (so this event isn't fired), when the payment is added. So the only way to place the order in onNotify(), is to "apply the transition" to the order and then save the order yourself - but then we're back to the concurrency problem above, unfortunately, since both onNotify() and onReturn() saves the order. (And i guess we would also have been back to that problem, if commerce placed the order by itself)
Score:1
ธง cn

คุณพูดถูกเกี่ยวกับสภาพการแข่งขัน แต่ onReturn ไม่แก้ไขคำสั่งซื้อเลย

นี่คือสิ่งที่เกิดขึ้นในพื้นหลัง:

  • เดอะ commerce_payment.checkout.return เส้นทางการชำระเงินเชิงพาณิชย์ เรียกว่าโมดูลซึ่งในตอนแรกให้ปลั๊กอินเกตเวย์การชำระเงินของคำสั่งซื้อ เพื่อสร้างการชำระเงินสำหรับการสั่งซื้อ
  • ไม่ว่าอะไรจะเกิดขึ้นในเมธอด onReturn ของโฟลว์การเช็คเอาต์คำสั่งปลั๊กอินจะถูกเปลี่ยนเส้นทางไปยังสเตจอื่น (หาก onReturn แสดงข้อยกเว้น มันจะถูกเปลี่ยนเส้นทางไปยังสเตจก่อนหน้า มิฉะนั้นจะถูกเปลี่ยนเส้นทางไปยังสเตจถัดไป)
  • ในสถานการณ์นี้วิธีการ เปลี่ยนเส้นทางไปที่ขั้นตอน ใน Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowBase จะแก้ไขและบันทึกคำสั่งซื้อซึ่งเป็นจุดที่เกิดปัญหา

นี่คือการดำเนินการของ เปลี่ยนเส้นทางไปที่ขั้นตอน:

/**
 * {@inheritdoc}
 */
ฟังก์ชั่นสาธารณะ redirectToStep ($ step_id) {
  ถ้า (!$this->isStepVisible($step_id)) {
    โยนใหม่ \InvalidArgumentException(sprintf('รหัสขั้นตอนไม่ถูกต้อง "%s" ที่ส่งผ่านไปยัง redirectToStep().', $step_id));
  }

  $this->order->set('checkout_step', $step_id);
  $this->onStepChange($step_id);
  $this->order->save();

  โยน NeedsRedirectException ใหม่ (Url::fromRoute ('commerce_checkout.form', [
    'commerce_order' => $this->order->id(),
    'ขั้นตอน' => $step_id,
  ])->toString());
}

ดังนั้นเพื่อแก้ปัญหาในวิธีการ onReturn ของคุณคุณควรยืนหยัดเพื่อ onNotify การเปลี่ยนแปลงที่จะทำ (การวนซ้ำในขณะที่รอจนกว่าจะมีการตั้งค่าการเปลี่ยนแปลงตามคำสั่ง)

หวังว่ามันจะช่วยได้

jp flag
ขอบคุณสำหรับคำตอบที่ดีของคุณ! มีคำถามหนึ่งข้อ - แม้ว่าฉันจะรอ onReturn เพื่อให้การเปลี่ยนแปลง onNotify เสร็จสิ้น แต่ "$ this->order" จะไม่ยังคงมีค่าเก่าก่อนที่จะเรียกใช้ onNotify หรือไม่ (ดังนั้น redirectToStep จะบันทึกค่าเก่า) หากเป็นเช่นนั้น มีวิธีรีโหลด "$this->order" ใน onReturn (หลังจากรอ) หรือไม่
jp flag
(อืม...และไม่สามารถบันทึกคำสั่งซื้อใน onNotify จริง ๆ แล้วเปลี่ยนกลับการเปลี่ยนแปลงเป็น "checkout_step" ในคำสั่งซื้อที่เปลี่ยนเส้นทางไปยังขั้นตอนเป็นค่าเดิมหรือไม่)
Alireza Tabatabaeian avatar
cn flag
จริงๆ แล้วฉันไม่ค่อยแน่ใจนักเกี่ยวกับสถานการณ์นี้ แต่ฉันเดาว่ามันน่าจะใช้ได้ โอเค ลองทำดูและหากสิ่งต่างๆ ไม่เป็นไปด้วยดี เราก็สามารถคิดถึงแนวทางอื่นๆ ได้

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา