SlideShare a Scribd company logo
1 of 40
Checkout
demystified
Spryker User Group
Berlin
27.01.2020
Damijan Ćavar
About me
2
− 20+ years of experience
− 3+ years at Spryker
− Project experience with various stack
− Project experience with multiple industries
− ...
What will we learn?
3
− How to place an Order?
− What is a step engine?
− Why is do we need step engine?
− How to implements a new step?
− Where do we modify the Quote?
− What happens it something goes wrong?
− ...
Quote transfer lifetime
4
What is a checkout?
5
− Step is a class that implements the StepInterface and handles the data.
What is a step?
6
StepInterface
7
public function preCondition(AbstractTransfer $quoteTransfer);
public function requireInput(AbstractTransfer $dataTransfer);
public function execute(Request $request, AbstractTransfer $dataTransfer);
public function postCondition(AbstractTransfer $dataTransfer);
public function getStepRoute();
public function getEscapeRoute();
public function getTemplateVariables(AbstractTransfer $dataTransfer);
preCondition method
8
Preconditions are called before each step. If the condition is met then it will return true and the process
will continue. If it returns false, the customer will be redirected to the escape route defined for this step.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function preCondition(AbstractTransfer $quoteTransfer)
{
if ($this->isCartEmpty($quoteTransfer)) {
return false;
}
if (!$quoteTransfer->getCheckoutConfirmed()) {
$this->escapeRoute = CheckoutPageControllerProvider::CHECKOUT_SUMMARY;
return false;
}
return true;
}
requireInput method
9
In this method we determine if step requires user input. If input methods return true we will render the
form and wait for user input.
/**
* Require input for customer authentication if the customer is not logged in already, or haven't authenticated yet.
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function requireInput(AbstractTransfer $quoteTransfer)
{
if ($this->isCustomerLoggedIn()) {
return false;
}
return true;
}
execute method
10
If the form is valid, the updated QuoteTransfer is passed to Step::execute() method where you can
modify it further or apply custom logic (call a client or Zed). Also, there is Symfony Request object
passed if additional/manual data mapping is required.
/**
* Update QuoteTransfer with customer step handler plugin.
*
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function execute(Request $request, AbstractTransfer $quoteTransfer)
{
return $this->customerStepHandler->addToDataClass($request, $quoteTransfer);
}
postCondition method
11
Post condition is an essential part of the step Processing. It indicates if a step has all the data that it
needs and if its requirements are satisfied.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return bool
*/
public function postCondition(AbstractTransfer $quoteTransfer)
{
if ($this->hasOnlyGiftCardItems($quoteTransfer)) {
return true;
}
if (!$this->isShipmentSet($quoteTransfer)) {
return false;
}
return true;
}
Do not modify the Quote in postCondition!!!
getTemplateVariables method
12
With this method we can provide additional parameters that we might want to render on the template.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getTemplateVariables(AbstractTransfer $quoteTransfer)
{
return [
'quoteTransfer' => $quoteTransfer,
'cartItems' => $this->productBundleClient->getGroupedBundleItems(
$quoteTransfer->getItems(),
$quoteTransfer->getBundleItems()
),
];
}
getStepRoute and getEscapeRoute methods
13
Step route is the route to the step and
escape route is where we redirect in case of an error.
/**
* @return string
*/
public function getStepRoute()
{
return $this->stepRoute;
}
/**
* @return string
*/
public function getEscapeRoute()
{
return $this->escapeRoute;
}
Step collection
14
interface StepCollectionInterface extends IteratorAggregate
{
public function addStep(StepInterface $step);
public function canAccessStep(StepInterface $step, Request $request, AbstractTransfer $dataTransfer);
public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer);
public function getNextStep(StepInterface $currentStep);
public function getPreviousStep(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null);
public function getCurrentUrl(StepInterface $currentStep);
public function getNextUrl(StepInterface $currentStep, AbstractTransfer $dataTransfer);
public function getPreviousUrl(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null);
public function getEscapeUrl(StepInterface $currentStep);
}
Step collection
15
Step engine accesses step through step engine. Order of steps is also defined by collection.
canAccessStep method
16
With this method we determine if we can access a step or not. We can access it only if previous steps
were completed successfully.
/**
* @param SprykerYvesStepEngineDependencyStepStepInterface $currentStep
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $dataTransfer
*
* @return bool
*/
public function canAccessStep(StepInterface $currentStep, Request $request, AbstractTransfer $dataTransfer)
{
if ($request->get('_route') === $currentStep->getStepRoute()) {
return true;
}
foreach ($this->getCompletedSteps($dataTransfer) as $step) {
if ($step->getStepRoute() === $request->get('_route')) {
return true;
}
}
return false;
}
getCurrentStep method
17
This method will return the last not completed step by checking the post condition of steps.
/**
* @param SymfonyComponentHttpFoundationRequest $request
* @param GeneratedSharedTransferQuoteTransfer $dataTransfer
*
* @return SprykerYvesStepEngineDependencyStepStepInterface
*/
public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer)
{
foreach ($this->steps as $step) {
if (!$step->postCondition($dataTransfer) || $request->get('_route') === $step->getStepRoute()) {
return $step;
}
$this->completedSteps[] = $step;
}
return end($this->completedSteps);
}
Form collection
18
Form collection
19
This class is responsible for forms rendering and data binding.
interface FormCollectionHandlerInterface
{
public function getForms(AbstractTransfer $dataTransfer);
public function hasSubmittedForm(Request $request, AbstractTransfer $dataTransfer);
public function handleRequest(Request $request, AbstractTransfer $dataTransfer);
public function provideDefaultFormData(AbstractTransfer $dataTransfer);
}
handleRequest method
20
After form has been submitted we validate the input and populate the underlying data object.
public function handleRequest(Request $request, AbstractTransfer $dataTransfer)
{
foreach ($this->getForms($dataTransfer) as $form) {
if ($request->request->has($form->getName())) {
$form->setData($dataTransfer);
return $form->handleRequest($request);
}
}
throw new InvalidFormHandleRequest('Form to handle not found in Request.');
}
data Providers
21
If we need to provide additional data to the form we use dataProviders
interface StepEngineFormDataProviderInterface
{
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function getData(AbstractTransfer $quoteTransfer);
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getOptions(AbstractTransfer $quoteTransfer);
}
getData method
22
In this method we can do a some business logic before setting values to quote.
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return SprykerSharedKernelTransferAbstractTransfer
*/
public function getData(AbstractTransfer $quoteTransfer)
{
$quoteTransfer->setShippingAddress($this->getShippingAddress($quoteTransfer));
$quoteTransfer->setBillingAddress($this->getBillingAddress($quoteTransfer));
$quoteTransfer->setBillingSameAsShipping(
$this->isSameAddress($quoteTransfer->getShippingAddress(), $quoteTransfer->getBillingAddress())
);
return $quoteTransfer;
}
getOptions
23
If we need to populate dropdowns (call Zed) or have business rules that we need to apply then we do it
in getOptions
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return array
*/
public function getOptions(AbstractTransfer $quoteTransfer)
{
return [
CheckoutAddressCollectionForm::OPTION_ADDRESS_CHOICES => $this->getAddressChoices(),
CheckoutAddressCollectionForm::OPTION_COUNTRY_CHOICES => $this->getAvailableCountries(),
];
}
Data container
24
dataContainer
25
DataContainer is a simple wrapper around quote persistence. Depending on the selected strategy it
can be either Redis or DB (or you can have your own custom implementation)
interface DataContainerInterface
{
/**
* @return GeneratedSharedTransferQuoteTransfer
*/
public function get();
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return void
*/
public function set(AbstractTransfer $quoteTransfer);
}
Step engine
26
interface StepEngineInterface
{
/**
* @param SymfonyComponentHttpFoundationRequest $request
* @param SprykerYvesStepEngineFormFormCollectionHandlerInterface|null $formCollection
*
* @return array|SymfonyComponentHttpFoundationRedirectResponse
*/
public function process(Request $request, ?FormCollectionHandlerInterface $formCollection = null);
}
Step engine
27
Step engine
28
Workflow
29
Code
30
https://github.com/spryker/step-
engine/blob/master/src/Spryker/Yves/StepEn
gine/Process/StepEngine.php#L73
Placing the order
31
Checkout workflow
32
interface CheckoutWorkflowInterface
{
/**
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferCheckoutResponseTransfer
*/
public function placeOrder(QuoteTransfer $quoteTransfer);
}
After we are through the checkout we still need to place the order. We need to transform Quote into Order
and store it into database. That is done in Checkout workflow on Zed.
Place the order
33
public function placeOrder(QuoteTransfer $quoteTransfer)
{
$checkoutResponseTransfer = $this->createCheckoutResponseTransfer();
if (!$this->checkPreConditions($quoteTransfer, $checkoutResponseTransfer)) {
return $checkoutResponseTransfer;
}
$quoteTransfer = $this->doPreSave($quoteTransfer, $checkoutResponseTransfer);
$quoteTransfer = $this->doSaveOrder($quoteTransfer, $checkoutResponseTransfer);
$this->runStateMachine($checkoutResponseTransfer->getSaveOrder());
$this->doPostSave($quoteTransfer, $checkoutResponseTransfer);
return $checkoutResponseTransfer;
}
− check preconditions (is quote still valid)
− presave (any additional info)
− saving the order
− post save
You only have 30s !!!
checkCondition method
34
interface CheckoutPreConditionPluginInterface
{
/**
* Specification:
* - Checks a condition before the order is saved.
* - Returns "false" and adds error to response transfer when condition failso.
* - Returns "true" when condition passed. Can add errors to response transfer.
* - Does not change Quote transfer.
* - Does not write to Persistence.
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponseTransfer
*
* @return bool
*/
public function checkCondition(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer
$checkoutResponseTransfer);
}
check if Quote is still valid
preSave method
35
interface CheckoutPreSaveInterface
{
/**
* Specification:
* - Do something before orderTransfer save
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
*
* @return GeneratedSharedTransferQuoteTransfer
*/
public function preSave(QuoteTransfer $quoteTransfer);
}
expand the quote with additional info
saveOrder method
36
interface CheckoutDoSaveOrderInterface
{
/**
* Specification:
* - Retrieves (its) data from the quote object and saves it to the database.
* - These plugins are already enveloped into a transaction.
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferSaveOrderTransfer $saveOrderTransfer
*
* @return void
*/
public function saveOrder(QuoteTransfer $quoteTransfer, SaveOrderTransfer $saveOrderTransfer);
}
persist checked and expanded Quote to database - place an order.
postSave method
37
interface CheckoutPostSaveHookInterface
{
/**
* Specification:
* - This plugin is called after the order is placed.
* - Set the success flag to false, if redirect should be headed to an error page afterwords
*
* @api
*
* @param GeneratedSharedTransferQuoteTransfer $quoteTransfer
* @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponse
*
* @return void
*/
public function executeHook(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer
$checkoutResponse);
}
if we need to make an action after order is placed.
questions?
38
39
The Spryker Commerce
OS is a “beyond shop -
beyond desktop”
commerce technology,
enabling transactional
use cases at every
touchpoint today and in
future.
Contact us
spryker.com
hello@spryker.com
@sprysys
+49 (30) 2084983 53

More Related Content

What's hot

Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
Spark Summit
 
Stationary Fuel Cell Lab Report
Stationary Fuel Cell Lab ReportStationary Fuel Cell Lab Report
Stationary Fuel Cell Lab Report
Janet Mok
 
C++정리 스마트포인터
C++정리 스마트포인터C++정리 스마트포인터
C++정리 스마트포인터
fefe7270
 

What's hot (20)

G1 Garbage Collector: Details and Tuning
G1 Garbage Collector: Details and TuningG1 Garbage Collector: Details and Tuning
G1 Garbage Collector: Details and Tuning
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Live Coding Spring, Kafka, & Elasticsearch: Personalized Search Results on Ra...
Live Coding Spring, Kafka, & Elasticsearch: Personalized Search Results on Ra...Live Coding Spring, Kafka, & Elasticsearch: Personalized Search Results on Ra...
Live Coding Spring, Kafka, & Elasticsearch: Personalized Search Results on Ra...
 
ORACLE_23-03-31_en.pdf
ORACLE_23-03-31_en.pdfORACLE_23-03-31_en.pdf
ORACLE_23-03-31_en.pdf
 
Apache Flink @ NYC Flink Meetup
Apache Flink @ NYC Flink MeetupApache Flink @ NYC Flink Meetup
Apache Flink @ NYC Flink Meetup
 
Understand more about C
Understand more about CUnderstand more about C
Understand more about C
 
How to Schedule Automated Tasks in Drupal with Cron?
How to Schedule Automated Tasks in Drupal with Cron?How to Schedule Automated Tasks in Drupal with Cron?
How to Schedule Automated Tasks in Drupal with Cron?
 
Epoll - from the kernel side
Epoll -  from the kernel sideEpoll -  from the kernel side
Epoll - from the kernel side
 
Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
Cost-Based Optimizer Framework for Spark SQL: Spark Summit East talk by Ron H...
 
Stationary Fuel Cell Lab Report
Stationary Fuel Cell Lab ReportStationary Fuel Cell Lab Report
Stationary Fuel Cell Lab Report
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
C++정리 스마트포인터
C++정리 스마트포인터C++정리 스마트포인터
C++정리 스마트포인터
 
Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)Domain Modeling with FP (DDD Europe 2020)
Domain Modeling with FP (DDD Europe 2020)
 
Async History - javascript
Async History - javascriptAsync History - javascript
Async History - javascript
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Understaing Android EGL
Understaing Android EGLUnderstaing Android EGL
Understaing Android EGL
 
Analyzing Time Series Data with Apache Spark and Cassandra
Analyzing Time Series Data with Apache Spark and CassandraAnalyzing Time Series Data with Apache Spark and Cassandra
Analyzing Time Series Data with Apache Spark and Cassandra
 
Dapper performance
Dapper performanceDapper performance
Dapper performance
 
Software Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdfSoftware Craftsmanship @Code Camp Festival 2022.pdf
Software Craftsmanship @Code Camp Festival 2022.pdf
 
[2019] Java에서 Fiber를 이용하여 동시성concurrency 프로그래밍 쉽게 하기
[2019] Java에서 Fiber를 이용하여 동시성concurrency 프로그래밍 쉽게 하기[2019] Java에서 Fiber를 이용하여 동시성concurrency 프로그래밍 쉽게 하기
[2019] Java에서 Fiber를 이용하여 동시성concurrency 프로그래밍 쉽게 하기
 

Similar to Chekout demistified

Step By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts AppStep By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts App
Syed Shahul
 
CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)
brian d foy
 

Similar to Chekout demistified (20)

Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w LaraveluLaravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
Laravel Poznań Meetup #2 - Wykorzystanie FormRequest w Laravelu
 
Wykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w LaraveluWykorzystanie form request przy implementacji API w Laravelu
Wykorzystanie form request przy implementacji API w Laravelu
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and SimpleDrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
DrupalJam 2018 - Maintaining a Drupal Module: Keep It Small and Simple
 
Step By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts AppStep By Step Guide For Buidling Simple Struts App
Step By Step Guide For Buidling Simple Struts App
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
What's new in jQuery 1.5
What's new in jQuery 1.5What's new in jQuery 1.5
What's new in jQuery 1.5
 
Mashing up JavaScript
Mashing up JavaScriptMashing up JavaScript
Mashing up JavaScript
 
Spring MVC Annotations
Spring MVC AnnotationsSpring MVC Annotations
Spring MVC Annotations
 
CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)CGI::Prototype (NPW 2006)
CGI::Prototype (NPW 2006)
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
 

Recently uploaded

Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptxChiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
raffaeleoman
 
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
Sheetaleventcompany
 
If this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New NigeriaIf this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New Nigeria
Kayode Fayemi
 

Recently uploaded (20)

Call Girl Number in Khar Mumbai📲 9892124323 💞 Full Night Enjoy
Call Girl Number in Khar Mumbai📲 9892124323 💞 Full Night EnjoyCall Girl Number in Khar Mumbai📲 9892124323 💞 Full Night Enjoy
Call Girl Number in Khar Mumbai📲 9892124323 💞 Full Night Enjoy
 
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptxChiulli_Aurora_Oman_Raffaele_Beowulf.pptx
Chiulli_Aurora_Oman_Raffaele_Beowulf.pptx
 
BDSM⚡Call Girls in Sector 97 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 97 Noida Escorts >༒8448380779 Escort ServiceBDSM⚡Call Girls in Sector 97 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 97 Noida Escorts >༒8448380779 Escort Service
 
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdfThe workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
The workplace ecosystem of the future 24.4.2024 Fabritius_share ii.pdf
 
Re-membering the Bard: Revisiting The Compleat Wrks of Wllm Shkspr (Abridged)...
Re-membering the Bard: Revisiting The Compleat Wrks of Wllm Shkspr (Abridged)...Re-membering the Bard: Revisiting The Compleat Wrks of Wllm Shkspr (Abridged)...
Re-membering the Bard: Revisiting The Compleat Wrks of Wllm Shkspr (Abridged)...
 
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
No Advance 8868886958 Chandigarh Call Girls , Indian Call Girls For Full Nigh...
 
SaaStr Workshop Wednesday w/ Lucas Price, Yardstick
SaaStr Workshop Wednesday w/ Lucas Price, YardstickSaaStr Workshop Wednesday w/ Lucas Price, Yardstick
SaaStr Workshop Wednesday w/ Lucas Price, Yardstick
 
Mohammad_Alnahdi_Oral_Presentation_Assignment.pptx
Mohammad_Alnahdi_Oral_Presentation_Assignment.pptxMohammad_Alnahdi_Oral_Presentation_Assignment.pptx
Mohammad_Alnahdi_Oral_Presentation_Assignment.pptx
 
ANCHORING SCRIPT FOR A CULTURAL EVENT.docx
ANCHORING SCRIPT FOR A CULTURAL EVENT.docxANCHORING SCRIPT FOR A CULTURAL EVENT.docx
ANCHORING SCRIPT FOR A CULTURAL EVENT.docx
 
Microsoft Copilot AI for Everyone - created by AI
Microsoft Copilot AI for Everyone - created by AIMicrosoft Copilot AI for Everyone - created by AI
Microsoft Copilot AI for Everyone - created by AI
 
George Lever - eCommerce Day Chile 2024
George Lever -  eCommerce Day Chile 2024George Lever -  eCommerce Day Chile 2024
George Lever - eCommerce Day Chile 2024
 
Air breathing and respiratory adaptations in diver animals
Air breathing and respiratory adaptations in diver animalsAir breathing and respiratory adaptations in diver animals
Air breathing and respiratory adaptations in diver animals
 
If this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New NigeriaIf this Giant Must Walk: A Manifesto for a New Nigeria
If this Giant Must Walk: A Manifesto for a New Nigeria
 
Governance and Nation-Building in Nigeria: Some Reflections on Options for Po...
Governance and Nation-Building in Nigeria: Some Reflections on Options for Po...Governance and Nation-Building in Nigeria: Some Reflections on Options for Po...
Governance and Nation-Building in Nigeria: Some Reflections on Options for Po...
 
Report Writing Webinar Training
Report Writing Webinar TrainingReport Writing Webinar Training
Report Writing Webinar Training
 
VVIP Call Girls Nalasopara : 9892124323, Call Girls in Nalasopara Services
VVIP Call Girls Nalasopara : 9892124323, Call Girls in Nalasopara ServicesVVIP Call Girls Nalasopara : 9892124323, Call Girls in Nalasopara Services
VVIP Call Girls Nalasopara : 9892124323, Call Girls in Nalasopara Services
 
BDSM⚡Call Girls in Sector 93 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 93 Noida Escorts >༒8448380779 Escort ServiceBDSM⚡Call Girls in Sector 93 Noida Escorts >༒8448380779 Escort Service
BDSM⚡Call Girls in Sector 93 Noida Escorts >༒8448380779 Escort Service
 
Night 7k Call Girls Noida Sector 128 Call Me: 8448380779
Night 7k Call Girls Noida Sector 128 Call Me: 8448380779Night 7k Call Girls Noida Sector 128 Call Me: 8448380779
Night 7k Call Girls Noida Sector 128 Call Me: 8448380779
 
Mathematics of Finance Presentation.pptx
Mathematics of Finance Presentation.pptxMathematics of Finance Presentation.pptx
Mathematics of Finance Presentation.pptx
 
Presentation on Engagement in Book Clubs
Presentation on Engagement in Book ClubsPresentation on Engagement in Book Clubs
Presentation on Engagement in Book Clubs
 

Chekout demistified

  • 2. About me 2 − 20+ years of experience − 3+ years at Spryker − Project experience with various stack − Project experience with multiple industries − ...
  • 3. What will we learn? 3 − How to place an Order? − What is a step engine? − Why is do we need step engine? − How to implements a new step? − Where do we modify the Quote? − What happens it something goes wrong? − ...
  • 5. What is a checkout? 5
  • 6. − Step is a class that implements the StepInterface and handles the data. What is a step? 6
  • 7. StepInterface 7 public function preCondition(AbstractTransfer $quoteTransfer); public function requireInput(AbstractTransfer $dataTransfer); public function execute(Request $request, AbstractTransfer $dataTransfer); public function postCondition(AbstractTransfer $dataTransfer); public function getStepRoute(); public function getEscapeRoute(); public function getTemplateVariables(AbstractTransfer $dataTransfer);
  • 8. preCondition method 8 Preconditions are called before each step. If the condition is met then it will return true and the process will continue. If it returns false, the customer will be redirected to the escape route defined for this step. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function preCondition(AbstractTransfer $quoteTransfer) { if ($this->isCartEmpty($quoteTransfer)) { return false; } if (!$quoteTransfer->getCheckoutConfirmed()) { $this->escapeRoute = CheckoutPageControllerProvider::CHECKOUT_SUMMARY; return false; } return true; }
  • 9. requireInput method 9 In this method we determine if step requires user input. If input methods return true we will render the form and wait for user input. /** * Require input for customer authentication if the customer is not logged in already, or haven't authenticated yet. * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function requireInput(AbstractTransfer $quoteTransfer) { if ($this->isCustomerLoggedIn()) { return false; } return true; }
  • 10. execute method 10 If the form is valid, the updated QuoteTransfer is passed to Step::execute() method where you can modify it further or apply custom logic (call a client or Zed). Also, there is Symfony Request object passed if additional/manual data mapping is required. /** * Update QuoteTransfer with customer step handler plugin. * * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function execute(Request $request, AbstractTransfer $quoteTransfer) { return $this->customerStepHandler->addToDataClass($request, $quoteTransfer); }
  • 11. postCondition method 11 Post condition is an essential part of the step Processing. It indicates if a step has all the data that it needs and if its requirements are satisfied. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return bool */ public function postCondition(AbstractTransfer $quoteTransfer) { if ($this->hasOnlyGiftCardItems($quoteTransfer)) { return true; } if (!$this->isShipmentSet($quoteTransfer)) { return false; } return true; } Do not modify the Quote in postCondition!!!
  • 12. getTemplateVariables method 12 With this method we can provide additional parameters that we might want to render on the template. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getTemplateVariables(AbstractTransfer $quoteTransfer) { return [ 'quoteTransfer' => $quoteTransfer, 'cartItems' => $this->productBundleClient->getGroupedBundleItems( $quoteTransfer->getItems(), $quoteTransfer->getBundleItems() ), ]; }
  • 13. getStepRoute and getEscapeRoute methods 13 Step route is the route to the step and escape route is where we redirect in case of an error. /** * @return string */ public function getStepRoute() { return $this->stepRoute; } /** * @return string */ public function getEscapeRoute() { return $this->escapeRoute; }
  • 15. interface StepCollectionInterface extends IteratorAggregate { public function addStep(StepInterface $step); public function canAccessStep(StepInterface $step, Request $request, AbstractTransfer $dataTransfer); public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer); public function getNextStep(StepInterface $currentStep); public function getPreviousStep(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null); public function getCurrentUrl(StepInterface $currentStep); public function getNextUrl(StepInterface $currentStep, AbstractTransfer $dataTransfer); public function getPreviousUrl(StepInterface $currentStep, ?AbstractTransfer $dataTransfer = null); public function getEscapeUrl(StepInterface $currentStep); } Step collection 15 Step engine accesses step through step engine. Order of steps is also defined by collection.
  • 16. canAccessStep method 16 With this method we determine if we can access a step or not. We can access it only if previous steps were completed successfully. /** * @param SprykerYvesStepEngineDependencyStepStepInterface $currentStep * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $dataTransfer * * @return bool */ public function canAccessStep(StepInterface $currentStep, Request $request, AbstractTransfer $dataTransfer) { if ($request->get('_route') === $currentStep->getStepRoute()) { return true; } foreach ($this->getCompletedSteps($dataTransfer) as $step) { if ($step->getStepRoute() === $request->get('_route')) { return true; } } return false; }
  • 17. getCurrentStep method 17 This method will return the last not completed step by checking the post condition of steps. /** * @param SymfonyComponentHttpFoundationRequest $request * @param GeneratedSharedTransferQuoteTransfer $dataTransfer * * @return SprykerYvesStepEngineDependencyStepStepInterface */ public function getCurrentStep(Request $request, AbstractTransfer $dataTransfer) { foreach ($this->steps as $step) { if (!$step->postCondition($dataTransfer) || $request->get('_route') === $step->getStepRoute()) { return $step; } $this->completedSteps[] = $step; } return end($this->completedSteps); }
  • 19. Form collection 19 This class is responsible for forms rendering and data binding. interface FormCollectionHandlerInterface { public function getForms(AbstractTransfer $dataTransfer); public function hasSubmittedForm(Request $request, AbstractTransfer $dataTransfer); public function handleRequest(Request $request, AbstractTransfer $dataTransfer); public function provideDefaultFormData(AbstractTransfer $dataTransfer); }
  • 20. handleRequest method 20 After form has been submitted we validate the input and populate the underlying data object. public function handleRequest(Request $request, AbstractTransfer $dataTransfer) { foreach ($this->getForms($dataTransfer) as $form) { if ($request->request->has($form->getName())) { $form->setData($dataTransfer); return $form->handleRequest($request); } } throw new InvalidFormHandleRequest('Form to handle not found in Request.'); }
  • 21. data Providers 21 If we need to provide additional data to the form we use dataProviders interface StepEngineFormDataProviderInterface { /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function getData(AbstractTransfer $quoteTransfer); /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getOptions(AbstractTransfer $quoteTransfer); }
  • 22. getData method 22 In this method we can do a some business logic before setting values to quote. /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return SprykerSharedKernelTransferAbstractTransfer */ public function getData(AbstractTransfer $quoteTransfer) { $quoteTransfer->setShippingAddress($this->getShippingAddress($quoteTransfer)); $quoteTransfer->setBillingAddress($this->getBillingAddress($quoteTransfer)); $quoteTransfer->setBillingSameAsShipping( $this->isSameAddress($quoteTransfer->getShippingAddress(), $quoteTransfer->getBillingAddress()) ); return $quoteTransfer; }
  • 23. getOptions 23 If we need to populate dropdowns (call Zed) or have business rules that we need to apply then we do it in getOptions /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return array */ public function getOptions(AbstractTransfer $quoteTransfer) { return [ CheckoutAddressCollectionForm::OPTION_ADDRESS_CHOICES => $this->getAddressChoices(), CheckoutAddressCollectionForm::OPTION_COUNTRY_CHOICES => $this->getAvailableCountries(), ]; }
  • 25. dataContainer 25 DataContainer is a simple wrapper around quote persistence. Depending on the selected strategy it can be either Redis or DB (or you can have your own custom implementation) interface DataContainerInterface { /** * @return GeneratedSharedTransferQuoteTransfer */ public function get(); /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return void */ public function set(AbstractTransfer $quoteTransfer); }
  • 27. interface StepEngineInterface { /** * @param SymfonyComponentHttpFoundationRequest $request * @param SprykerYvesStepEngineFormFormCollectionHandlerInterface|null $formCollection * * @return array|SymfonyComponentHttpFoundationRedirectResponse */ public function process(Request $request, ?FormCollectionHandlerInterface $formCollection = null); } Step engine 27
  • 32. Checkout workflow 32 interface CheckoutWorkflowInterface { /** * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferCheckoutResponseTransfer */ public function placeOrder(QuoteTransfer $quoteTransfer); } After we are through the checkout we still need to place the order. We need to transform Quote into Order and store it into database. That is done in Checkout workflow on Zed.
  • 33. Place the order 33 public function placeOrder(QuoteTransfer $quoteTransfer) { $checkoutResponseTransfer = $this->createCheckoutResponseTransfer(); if (!$this->checkPreConditions($quoteTransfer, $checkoutResponseTransfer)) { return $checkoutResponseTransfer; } $quoteTransfer = $this->doPreSave($quoteTransfer, $checkoutResponseTransfer); $quoteTransfer = $this->doSaveOrder($quoteTransfer, $checkoutResponseTransfer); $this->runStateMachine($checkoutResponseTransfer->getSaveOrder()); $this->doPostSave($quoteTransfer, $checkoutResponseTransfer); return $checkoutResponseTransfer; } − check preconditions (is quote still valid) − presave (any additional info) − saving the order − post save You only have 30s !!!
  • 34. checkCondition method 34 interface CheckoutPreConditionPluginInterface { /** * Specification: * - Checks a condition before the order is saved. * - Returns "false" and adds error to response transfer when condition failso. * - Returns "true" when condition passed. Can add errors to response transfer. * - Does not change Quote transfer. * - Does not write to Persistence. * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponseTransfer * * @return bool */ public function checkCondition(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer $checkoutResponseTransfer); } check if Quote is still valid
  • 35. preSave method 35 interface CheckoutPreSaveInterface { /** * Specification: * - Do something before orderTransfer save * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * * @return GeneratedSharedTransferQuoteTransfer */ public function preSave(QuoteTransfer $quoteTransfer); } expand the quote with additional info
  • 36. saveOrder method 36 interface CheckoutDoSaveOrderInterface { /** * Specification: * - Retrieves (its) data from the quote object and saves it to the database. * - These plugins are already enveloped into a transaction. * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferSaveOrderTransfer $saveOrderTransfer * * @return void */ public function saveOrder(QuoteTransfer $quoteTransfer, SaveOrderTransfer $saveOrderTransfer); } persist checked and expanded Quote to database - place an order.
  • 37. postSave method 37 interface CheckoutPostSaveHookInterface { /** * Specification: * - This plugin is called after the order is placed. * - Set the success flag to false, if redirect should be headed to an error page afterwords * * @api * * @param GeneratedSharedTransferQuoteTransfer $quoteTransfer * @param GeneratedSharedTransferCheckoutResponseTransfer $checkoutResponse * * @return void */ public function executeHook(QuoteTransfer $quoteTransfer, CheckoutResponseTransfer $checkoutResponse); } if we need to make an action after order is placed.
  • 39. 39 The Spryker Commerce OS is a “beyond shop - beyond desktop” commerce technology, enabling transactional use cases at every touchpoint today and in future.