mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Compare commits
16 commits
af71409850
...
098a79279d
Author | SHA1 | Date | |
---|---|---|---|
|
098a79279d | ||
|
c54fe336d8 | ||
|
df34b7f5c3 | ||
|
c6f95af15f | ||
|
ef031e593c | ||
|
fb576e3839 | ||
|
b48534fb00 | ||
|
049b31b611 | ||
|
5d5775e02b | ||
|
3836771dae | ||
|
8825a88764 | ||
|
f5c9c4298a | ||
|
32afcda616 | ||
|
7cf0939953 | ||
|
f65b72e653 | ||
|
1262ed2c56 |
8 changed files with 487 additions and 12 deletions
115
docs/inbox-notifications-guide.md
Normal file
115
docs/inbox-notifications-guide.md
Normal file
|
@ -0,0 +1,115 @@
|
|||
# WooCommerce Home Inbox Notifications Development Guide
|
||||
|
||||
This guide explains how to create and manage inbox notifications that appear in the WooCommerce Admin dashboard.
|
||||
|
||||
## Overview
|
||||
|
||||
The WooCommerce PayPal Payments plugin uses a structured system to create inbox notes through three main components: note definitions, note objects, and registration handling.
|
||||
|
||||
## Architecture
|
||||
|
||||
### 1. Define Inbox Notes
|
||||
|
||||
Inbox notes are defined as service configurations in `modules/ppcp-wc-gateway/services.php` (Service name: `wcgateway.settings.inbox-notes`). The system creates an array of `InboxNote` objects with the following properties:
|
||||
|
||||
- `title`: The note headline
|
||||
- `content`: The note body text
|
||||
- `type`: Note type (e.g., `Note::E_WC_ADMIN_NOTE_INFORMATIONAL`)
|
||||
- `name`: Unique identifier for the note
|
||||
- `status`: Note status (e.g., `Note::E_WC_ADMIN_NOTE_UNACTIONED`)
|
||||
- `is_enabled`: Boolean function to control visibility
|
||||
- `action`: An `InboxNoteAction` object for user interactions
|
||||
|
||||
### 2. Create Inbox Note Objects
|
||||
|
||||
Each inbox note is created using the `InboxNoteFactory` and `InboxNote` class. The constructor requires all the properties listed above.
|
||||
|
||||
### 3. Register Inbox Notes
|
||||
|
||||
The `InboxNoteRegistrar` handles the registration process by:
|
||||
- Creating WooCommerce `Note` objects from `InboxNote` definitions
|
||||
- Saving notes to display in the admin inbox
|
||||
- Managing note lifecycle (creation/deletion based on conditions)
|
||||
|
||||
### 4. Registration Hook
|
||||
|
||||
Inbox notes are registered via the `register_woo_inbox_notes` method in `WCGatewayModule`, which hooks into the `admin_init` action.
|
||||
|
||||
## Implementation Example
|
||||
|
||||
```php
|
||||
// In services.php
|
||||
'inbox-note.example' => static function ( ContainerInterface $container ): InboxNote {
|
||||
return $container->get( 'inbox-note.factory' )->create_note(
|
||||
__( 'Example Note Title', 'woocommerce-paypal-payments' ),
|
||||
__( 'This is the note content that appears in the inbox.', 'woocommerce-paypal-payments' ),
|
||||
Note::E_WC_ADMIN_NOTE_INFORMATIONAL,
|
||||
'example-note-unique-name',
|
||||
Note::E_WC_ADMIN_NOTE_UNACTIONED,
|
||||
static function () use ( $container ): bool {
|
||||
// Conditional logic to determine when note should be shown
|
||||
return true; // or your condition
|
||||
},
|
||||
new InboxNoteAction(
|
||||
'apply_now',
|
||||
__( 'Apply now', 'woocommerce-paypal-payments' ),
|
||||
'http://example.com/',
|
||||
Note::E_WC_ADMIN_NOTE_UNACTIONED,
|
||||
true
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
```
|
||||
|
||||
## Content Limitations
|
||||
|
||||
WooCommerce inbox notes have several restrictions:
|
||||
|
||||
### Character Limit
|
||||
- Content is automatically truncated at **320 characters** with "..."
|
||||
- No expansion option available in the UI
|
||||
- Reference: [WooCommerce Developer Blog ↗](https://developer.woocommerce.com/2021/11/10/introducing-a-320-character-limit-to-inbox-notes/)
|
||||
|
||||
### HTML Restrictions
|
||||
Only basic HTML tags are allowed:
|
||||
- `<strong>`, `<em>` for emphasis
|
||||
- `<a>` for links (with `href`, `rel`, `name`, `target`, `download` attributes)
|
||||
- `<br>`, `<p>` for formatting
|
||||
- Tags like `<sup>`, `<sub>`, `<span>` are stripped
|
||||
|
||||
### Workarounds
|
||||
- Use asterisks (*) for emphasis when HTML tags aren't supported
|
||||
- Keep messages concise and prioritize essential information
|
||||
- Place most important content within the first 320 characters
|
||||
|
||||
## Automatic Cleanup
|
||||
|
||||
The system includes automatic cleanup functionality:
|
||||
- Notes are deleted when their `is_enabled` condition becomes `false` (`InboxNoteRegistrar.php`)
|
||||
- This prevents stale notifications from persisting in the admin
|
||||
|
||||
## Actions
|
||||
|
||||
Notes can include user actions defined through the `InboxNoteAction` class. Actions appear as buttons in the inbox note and can:
|
||||
- Navigate to specific admin pages
|
||||
- Trigger custom functionality
|
||||
- Dismiss or acknowledge the notification
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use descriptive, unique names** for note identification
|
||||
2. **Implement proper conditional logic** in the `is_enabled` function
|
||||
3. **Keep content concise** due to the 320-character limit
|
||||
4. **Test note visibility conditions** thoroughly
|
||||
5. **Provide clear, actionable next steps** through note actions
|
||||
6. **Consider cleanup scenarios** when notes should be removed
|
||||
|
||||
## Existing Examples
|
||||
|
||||
The codebase includes several inbox note implementations:
|
||||
- PayPal Working Capital note
|
||||
- Settings migration notices
|
||||
- Feature announcements
|
||||
|
||||
These examples demonstrate conditional logic based on feature flags, user settings, and other criteria.
|
296
docs/woocommerce-tasks-guide.md
Normal file
296
docs/woocommerce-tasks-guide.md
Normal file
|
@ -0,0 +1,296 @@
|
|||
# WooCommerce Tasks and Todos Development Guide
|
||||
|
||||
This guide explains how to create and manage task items that appear in WooCommerce's "Things to do next" section, as well as in the "Things to do next" section of the plugin’s overview tab. The PayPal Payments plugin uses two distinct systems to cover different use cases.
|
||||
|
||||
## Overview
|
||||
|
||||
The plugin uses two separate task systems:
|
||||
|
||||
1. **WooCommerce Native Tasks System** - Integrates with WooCommerce's built-in task list
|
||||
2. **Plugin's React-Based Todos System** - Custom implementation for the PayPal settings interface
|
||||
|
||||
## WooCommerce Native Tasks System
|
||||
|
||||
### Architecture
|
||||
|
||||
Native WooCommerce tasks are managed through the `TaskRegistrar` system and appear in WooCommerce's main admin "Things to do next" section.
|
||||
|
||||
### Implementation
|
||||
|
||||
Tasks are registered via the `register_wc_tasks` method in `WCGatewayModule.php`, which:
|
||||
|
||||
1. Hooks into the `init` action for proper timing
|
||||
2. Retrieves simple redirect tasks from the container
|
||||
3. Uses the `TaskRegistrar` to register tasks with the 'extended' list
|
||||
4. Includes error handling and logging for registration failures
|
||||
|
||||
```php
|
||||
protected function register_wc_tasks( ContainerInterface $container ): void {
|
||||
add_action(
|
||||
'init',
|
||||
static function () use ( $container ): void {
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
try {
|
||||
$simple_redirect_tasks = $container->get( 'wcgateway.settings.wc-tasks.simple-redirect-tasks' );
|
||||
if ( empty( $simple_redirect_tasks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$task_registrar = $container->get( 'wcgateway.settings.wc-tasks.task-registrar' );
|
||||
$task_registrar->register( 'extended', $simple_redirect_tasks );
|
||||
} catch ( Exception $exception ) {
|
||||
$logger->error( "Failed to create a task in the 'Things to do next' section of WC. " . $exception->getMessage() );
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Task Configuration
|
||||
|
||||
Tasks are defined in `services.php` as service definitions. Each task configuration includes:
|
||||
|
||||
- `id`: Unique identifier for the task
|
||||
- `title`: Display title in the task list
|
||||
- `description`: Explanatory text for what the task accomplishes
|
||||
- `redirect_url`: URL where users are taken when they click the task
|
||||
|
||||
```php
|
||||
// Example: Pay Later messaging configuration task
|
||||
'wcgateway.settings.wc-tasks.pay-later-task-config' => static function( ContainerInterface $container ): array {
|
||||
$section_id = Settings::CONNECTION_TAB_ID;
|
||||
$pay_later_tab_id = Settings::PAY_LATER_TAB_ID;
|
||||
|
||||
if ( $container->has( 'paylater-configurator.is-available' ) && $container->get( 'paylater-configurator.is-available' ) ) {
|
||||
return array(
|
||||
array(
|
||||
'id' => 'pay-later-messaging-task',
|
||||
'title' => __( 'Configure PayPal Pay Later messaging', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'Decide where you want dynamic Pay Later messaging to show up and how you want it to look on your site.', 'woocommerce-paypal-payments' ),
|
||||
'redirect_url' => admin_url( "admin.php?page=wc-settings&tab=checkout§ion={$section_id}&ppcp-tab={$pay_later_tab_id}" ),
|
||||
),
|
||||
);
|
||||
}
|
||||
return array();
|
||||
},
|
||||
```
|
||||
|
||||
### Registration Process
|
||||
|
||||
The `TaskRegistrar` class handles task registration through the `register()` method:
|
||||
|
||||
```php
|
||||
public function register( string $list_id, array $tasks ): void {
|
||||
$task_lists = TaskLists::get_lists();
|
||||
if ( ! isset( $task_lists[ $list_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $tasks as $task ) {
|
||||
$added_task = TaskLists::add_task( $list_id, $task );
|
||||
if ( $added_task instanceof WP_Error ) {
|
||||
throw new RuntimeException( $added_task->get_error_message() );
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The registration process:
|
||||
- Validates the target task list exists
|
||||
- Iterates through task definitions
|
||||
- Uses WooCommerce's `TaskLists::add_task()` API
|
||||
- Handles registration errors with exceptions
|
||||
|
||||
## Plugin's React-Based Todos System
|
||||
|
||||
### Architecture
|
||||
|
||||
The custom todos system provides more advanced functionality and appears specifically in the PayPal Payments settings Overview tab.
|
||||
|
||||
### Components
|
||||
|
||||
1. **Backend Definition** - `TodosDefinition.php` contains todo configurations
|
||||
2. **REST API Endpoint** - `TodosRestEndpoint.php` handles CRUD operations
|
||||
3. **React Frontend** - `Todos.js` renders the user interface
|
||||
|
||||
### Todo Configuration
|
||||
|
||||
Each todo item in `TodosDefinition.php` requires the following properties:
|
||||
|
||||
```php
|
||||
public function get(): array {
|
||||
$eligibility_checks = $this->eligibilities->get_eligibility_checks();
|
||||
|
||||
$todo_items = array(
|
||||
'enable_fastlane' => array(
|
||||
'title' => __( 'Enable Fastlane', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'Accelerate your guest checkout with Fastlane by PayPal', 'woocommerce-paypal-payments' ),
|
||||
'isEligible' => $eligibility_checks['enable_fastlane'],
|
||||
'action' => array(
|
||||
'type' => 'tab',
|
||||
'tab' => 'payment_methods',
|
||||
'section' => 'ppcp-axo-gateway',
|
||||
'highlight' => 'ppcp-axo-gateway',
|
||||
),
|
||||
'priority' => 1,
|
||||
),
|
||||
'enable_pay_later_messaging' => array(
|
||||
'title' => __( 'Enable Pay Later messaging', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'Show Pay Later options to increase conversion.', 'woocommerce-paypal-payments' ),
|
||||
'isEligible' => $eligibility_checks['enable_pay_later_messaging'],
|
||||
'action' => array(
|
||||
'type' => 'tab',
|
||||
'tab' => 'pay_later',
|
||||
'section' => 'pay-later-messaging',
|
||||
),
|
||||
'priority' => 2,
|
||||
),
|
||||
// Additional todo items...
|
||||
);
|
||||
|
||||
return $todo_items;
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Features
|
||||
|
||||
The React-based system supports:
|
||||
|
||||
- **Eligibility Checks**: Dynamic visibility based on conditions
|
||||
- **Dismissal**: Users can dismiss individual todos
|
||||
- **Completion Tracking**: Automatic removal when tasks are completed
|
||||
- **Priority Ordering**: Control display order with priority values
|
||||
- **REST API**: Full CRUD operations via dedicated endpoints
|
||||
|
||||
### API Integration
|
||||
|
||||
The REST API provides endpoints for managing todos:
|
||||
|
||||
```php
|
||||
public function register_routes(): void {
|
||||
// GET/POST /todos - Get todos list and update dismissed todos
|
||||
register_rest_route(
|
||||
static::NAMESPACE,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_todos' ),
|
||||
'permission_callback' => array( $this, 'check_permission' ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_todos' ),
|
||||
'permission_callback' => array( $this, 'check_permission' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// POST /todos/reset - Reset dismissed todos
|
||||
register_rest_route(
|
||||
static::NAMESPACE,
|
||||
'/' . $this->rest_base . '/reset',
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'reset_todos' ),
|
||||
'permission_callback' => array( $this, 'check_permission' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The endpoints handle:
|
||||
- **GET /todos**: Fetching current todo list with eligibility filtering
|
||||
- **POST /todos**: Updating dismissed todo status
|
||||
- **POST /todos/reset**: Restoring all dismissed todos
|
||||
|
||||
### Frontend Rendering
|
||||
|
||||
The React component provides a complete todo management interface:
|
||||
|
||||
```jsx
|
||||
const Todos = ( { todos, resetTodos, dismissTodo } ) => {
|
||||
const [ isResetting, setIsResetting ] = useState( false );
|
||||
const [ activeModal, setActiveModal ] = useState( null );
|
||||
|
||||
// Reset handler for restoring dismissed todos
|
||||
const resetHandler = useCallback( async () => {
|
||||
setIsResetting( true );
|
||||
try {
|
||||
await resetTodos();
|
||||
} finally {
|
||||
setIsResetting( false );
|
||||
}
|
||||
}, [ resetTodos ] );
|
||||
|
||||
if ( ! todos?.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsCard
|
||||
className="ppcp-r-tab-overview-todo"
|
||||
title={ __( 'Things to do next', 'woocommerce-paypal-payments' ) }
|
||||
description={
|
||||
<>
|
||||
<p>
|
||||
{ __(
|
||||
'Complete these tasks to keep your store updated with the latest products and services.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
</p>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
onClick={ resetHandler }
|
||||
disabled={ isResetting }
|
||||
>
|
||||
<Icon icon={ reusableBlock } size={ 18 } />
|
||||
{ isResetting
|
||||
? __( 'Restoring…', 'woocommerce-paypal-payments' )
|
||||
: __( 'Restore dismissed Things To Do', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<TodoSettingsBlock
|
||||
todosData={ todos }
|
||||
setActiveModal={ setActiveModal }
|
||||
onDismissTodo={ dismissTodo }
|
||||
/>
|
||||
</SettingsCard>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Key features:
|
||||
- **Restore Functionality**: Users can restore dismissed todos
|
||||
- **Modal Integration**: Support for detailed todo actions
|
||||
- **Dismissal Handling**: Individual todo dismissal with state management
|
||||
- **Loading States**: Visual feedback during operations
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For WooCommerce Native Tasks
|
||||
|
||||
1. **Keep task definitions simple** - Use basic configuration only
|
||||
2. **Provide clear redirect URLs** - Direct users to relevant settings
|
||||
3. **Use descriptive IDs** - Include plugin prefix for uniqueness
|
||||
4. **Test with WooCommerce updates** - Ensure compatibility with core changes
|
||||
|
||||
### For Plugin React Todos
|
||||
|
||||
1. **Implement robust eligibility checks** - Prevent showing irrelevant todos
|
||||
2. **Use appropriate priority values** - Ensure logical ordering
|
||||
3. **Provide actionable descriptions** - Help users understand next steps
|
||||
4. **Handle edge cases** - Account for various plugin states
|
||||
5. **Test dismissal functionality** - Ensure proper state management
|
||||
|
||||
## Existing Examples
|
||||
|
||||
Both systems have multiple implementations in the codebase:
|
||||
- Onboarding completion tasks
|
||||
- Feature enablement todos
|
||||
- Configuration reminder items
|
||||
- Migration assistance tasks
|
||||
|
||||
These examples demonstrate various conditional logic patterns and user experience flows.
|
|
@ -10,6 +10,9 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
||||
|
||||
use WC_Cart;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
|
||||
|
@ -31,7 +34,8 @@ class ShippingPreferenceFactory {
|
|||
PurchaseUnit $purchase_unit,
|
||||
string $context,
|
||||
?WC_Cart $cart = null,
|
||||
string $funding_source = ''
|
||||
string $funding_source = '',
|
||||
?WC_Order $wc_order = null
|
||||
): string {
|
||||
$contains_physical_goods = $purchase_unit->contains_physical_goods();
|
||||
if ( ! $contains_physical_goods ) {
|
||||
|
@ -39,8 +43,12 @@ class ShippingPreferenceFactory {
|
|||
}
|
||||
|
||||
$has_shipping = null !== $purchase_unit->shipping();
|
||||
$needs_shipping = $cart && $cart->needs_shipping();
|
||||
$shipping_address_is_fixed = $needs_shipping && 'checkout' === $context;
|
||||
$needs_shipping = ( $wc_order && $this->wc_order_needs_shipping( $wc_order ) ) || ( $cart && $cart->needs_shipping() );
|
||||
$shipping_address_is_fixed = $needs_shipping && in_array( $context, array( 'checkout', 'pay-now' ), true );
|
||||
|
||||
if ( ! $needs_shipping ) {
|
||||
return ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING;
|
||||
}
|
||||
|
||||
if ( $shipping_address_is_fixed ) {
|
||||
// Checkout + no address given? Probably something weird happened, like no form validation?
|
||||
|
@ -61,4 +69,26 @@ class ShippingPreferenceFactory {
|
|||
|
||||
return ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE;
|
||||
}
|
||||
|
||||
protected function wc_order_needs_shipping( WC_Order $wc_order ): bool {
|
||||
// WC 9.9.0+.
|
||||
if ( method_exists( $wc_order, 'needs_shipping' ) ) {
|
||||
return $wc_order->needs_shipping();
|
||||
}
|
||||
|
||||
if ( ! wc_shipping_enabled() || wc_get_shipping_method_count( true ) === 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $wc_order->get_items() as $item ) {
|
||||
if ( $item instanceof WC_Order_Item_Product ) {
|
||||
$product = $item->get_product();
|
||||
if ( $product instanceof WC_Product && $product->needs_shipping() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,8 +103,9 @@ if ( blockEnabled ) {
|
|||
edit: descriptionElement,
|
||||
placeOrderButtonLabel: config.placeOrderButtonText,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
canMakePayment: ( cartData ) => {
|
||||
const total = cartData?.cartTotals?.total_price;
|
||||
return parseInt( total ) > 0;
|
||||
},
|
||||
supports: {
|
||||
features,
|
||||
|
|
|
@ -896,6 +896,9 @@ export default class PaymentButton {
|
|||
this.syncProductButtonsState();
|
||||
}
|
||||
);
|
||||
|
||||
// Ensure initial state is synced on page load
|
||||
this.syncProductButtonsState();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1929,7 +1929,7 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
|
||||
$in_stock = $product->is_in_stock();
|
||||
|
||||
if ( ! $in_stock && $product->is_type( 'variable' ) ) {
|
||||
if ( $product->is_type( 'variable' ) ) {
|
||||
/**
|
||||
* The method is defined in WC_Product_Variable class.
|
||||
*
|
||||
|
|
|
@ -440,7 +440,8 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$this->purchase_unit,
|
||||
$this->parsed_request_data['context'],
|
||||
WC()->cart,
|
||||
$funding_source
|
||||
$funding_source,
|
||||
$wc_order
|
||||
);
|
||||
|
||||
$action = in_array( $this->parsed_request_data['context'], $this->pay_now_contexts, true ) ?
|
||||
|
|
|
@ -5,10 +5,14 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
|
|||
|
||||
use Mockery;
|
||||
use WC_Cart;
|
||||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Product;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ExperienceContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class ShippingPreferenceFactoryTest extends TestCase
|
||||
{
|
||||
|
@ -18,6 +22,9 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
when('wc_shipping_enabled')->justReturn(true);
|
||||
when('wc_get_shipping_method_count')->justReturn(2);
|
||||
|
||||
$this->testee = new ShippingPreferenceFactory();
|
||||
}
|
||||
|
||||
|
@ -29,9 +36,10 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
string $context,
|
||||
?WC_Cart $cart,
|
||||
string $funding_source,
|
||||
?WC_Order $wc_order,
|
||||
string $expected_result
|
||||
) {
|
||||
$result = $this->testee->from_state($purchase_unit, $context, $cart, $funding_source);
|
||||
$result = $this->testee->from_state($purchase_unit, $context, $cart, $funding_source, $wc_order);
|
||||
|
||||
self::assertEquals($expected_result, $result);
|
||||
}
|
||||
|
@ -43,6 +51,7 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
'checkout',
|
||||
$this->createCart(true),
|
||||
'',
|
||||
null,
|
||||
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
];
|
||||
yield [
|
||||
|
@ -50,6 +59,7 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
'checkout',
|
||||
$this->createCart(false),
|
||||
'',
|
||||
null,
|
||||
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
yield [
|
||||
|
@ -57,6 +67,7 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
'checkout',
|
||||
$this->createCart(true),
|
||||
'',
|
||||
null,
|
||||
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
yield [
|
||||
|
@ -64,6 +75,7 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
'checkout',
|
||||
$this->createCart(true),
|
||||
'card',
|
||||
null,
|
||||
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
];
|
||||
yield [
|
||||
|
@ -71,34 +83,39 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
'product',
|
||||
null,
|
||||
'',
|
||||
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
null,
|
||||
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'pay-now',
|
||||
null,
|
||||
'venmo',
|
||||
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
$this->createWcOrder(false),
|
||||
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'pay-now',
|
||||
null,
|
||||
'venmo',
|
||||
ExperienceContext::SHIPPING_PREFERENCE_GET_FROM_FILE,
|
||||
$this->createWcOrder(true),
|
||||
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, Mockery::mock(Shipping::class)),
|
||||
'pay-now',
|
||||
null,
|
||||
'card',
|
||||
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS,
|
||||
$this->createWcOrder(true),
|
||||
ExperienceContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS
|
||||
];
|
||||
yield [
|
||||
$this->createPurchaseUnit(true, null),
|
||||
'pay-now',
|
||||
null,
|
||||
'card',
|
||||
$this->createWcOrder(false),
|
||||
ExperienceContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
];
|
||||
}
|
||||
|
@ -115,4 +132,16 @@ class ShippingPreferenceFactoryTest extends TestCase
|
|||
$cart->shouldReceive('needs_shipping')->andReturn($needsShipping);
|
||||
return $cart;
|
||||
}
|
||||
|
||||
private function createWcOrder(bool $needsShipping): WC_Order {
|
||||
$product = Mockery::mock(WC_Product::class);
|
||||
$product->shouldReceive('needs_shipping')->andReturn($needsShipping);
|
||||
|
||||
$item = Mockery::mock(WC_Order_Item_Product::class);
|
||||
$item->shouldReceive('get_product')->andReturn($product);
|
||||
|
||||
$wcOrder = Mockery::mock(WC_Order::class);
|
||||
$wcOrder->shouldReceive('get_items')->andReturn([$item]);
|
||||
return $wcOrder;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue