135 lines
4.5 KiB
PHP
135 lines
4.5 KiB
PHP
<?php
|
|
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
|
|
*
|
|
* This source code is licensed under the license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @package MetaCommerce
|
|
*/
|
|
|
|
namespace WooCommerce\Facebook\OfferManagement;
|
|
|
|
use WC_Coupon;
|
|
|
|
/**
|
|
* OfferManagement endpoint used by Meta to create new offers.
|
|
*/
|
|
class CreateOffersEndpoint extends OfferManagementEndpointBase {
|
|
|
|
final protected static function get_method(): string {
|
|
return 'POST';
|
|
}
|
|
|
|
final protected function execute_endpoint( array $params ): array {
|
|
$create_offers_data = self::get_params_value_enforced( 'create_offers_data', $params );
|
|
$created_offers = [];
|
|
foreach ( $create_offers_data as $create_offer_data ) {
|
|
try {
|
|
$coupon = self::create_coupon_from_offer_data( $create_offer_data );
|
|
if ( null === $coupon ) {
|
|
continue;
|
|
}
|
|
$coupon->add_meta_data( self::IS_FACEBOOK_MANAGED_METADATA_KEY, 'yes', true );
|
|
$coupon->save();
|
|
$created_offers[] = self::get_offer_response_data( $coupon );
|
|
} catch ( \Exception $ex ) {
|
|
$this->add_error( self::get_error_response_data( self::ERROR_OFFER_CREATE_FAILURE, $ex->getMessage(), $create_offer_data['code'] ) );
|
|
}
|
|
}
|
|
|
|
return [ 'created_offers' => $created_offers ];
|
|
}
|
|
|
|
/**
|
|
* @param array $create_offer_data
|
|
* @return ?WC_Coupon A WC_Coupon object if one was able to be created.
|
|
*/
|
|
private function create_coupon_from_offer_data( array $create_offer_data ): ?WC_Coupon {
|
|
$coupon = null;
|
|
$errors = [];
|
|
|
|
$code = $create_offer_data['code'];
|
|
$coupon_id = wc_get_coupon_id_by_code( $code );
|
|
if ( 0 !== $coupon_id ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CODE_ALREADY_EXISTS, '', $code );
|
|
}
|
|
|
|
// A target_type of line_item indicates the coupon applies to products.
|
|
$offer_class = $create_offer_data['offer_class'];
|
|
if ( 'order' !== $offer_class ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CONFIGURATION_NOT_SUPPORTED, 'Only product targeted coupons are supported', $code );
|
|
}
|
|
|
|
$percent_off = $create_offer_data['percent_off'] ?? 0;
|
|
$fixed_amount_off_input = $create_offer_data['fixed_amount_off'] ?? null;
|
|
|
|
// Exclusive or (XOR) on presence of percent off and fixed amount off.
|
|
if ( ( 0 === $percent_off ) === empty( $fixed_amount_off_input ) ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CREATE_FAILURE, 'Exactly one of fixed amount off or percent off is required', $code );
|
|
}
|
|
|
|
if ( 0 !== $percent_off ) {
|
|
if ( ! is_numeric( $percent_off ) || $percent_off < 0 ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CREATE_FAILURE, sprintf( 'Invalid percent off: %s', $percent_off ), $code );
|
|
}
|
|
$discount_type = 'percent';
|
|
$amount = $percent_off;
|
|
} else {
|
|
// Pass errors reference to add currency parsing errors.
|
|
$discount_type = 'fixed_cart';
|
|
$amount = $this->parse_currency_amount( $fixed_amount_off_input, $errors );
|
|
}
|
|
|
|
// Validation errors for the creation of this coupon.
|
|
if ( empty( $errors ) ) {
|
|
$coupon = new WC_Coupon( $code );
|
|
$coupon->set_props(
|
|
array(
|
|
'discount_type' => $discount_type,
|
|
'amount' => $amount,
|
|
'usage_limit' => $create_offer_data['usage_limit'] ?? 1,
|
|
)
|
|
);
|
|
$coupon->set_date_expires( $create_offer_data['end_time'] ?? null );
|
|
|
|
$tags = $create_offer_data['tags'] ?? [];
|
|
$coupon->add_meta_data( self::OFFER_TAGS, $tags );
|
|
|
|
if ( isset( $create_offer_data['email'] ) ) {
|
|
$coupon->set_email_restrictions( [ $create_offer_data['email'] ] );
|
|
}
|
|
}
|
|
|
|
foreach ( $errors as &$error ) {
|
|
$error['offer_code'] = $code;
|
|
}
|
|
|
|
$this->add_errors( $errors );
|
|
return $coupon;
|
|
}
|
|
|
|
|
|
public static function parse_currency_amount( ?array $amount_with_currency, array &$errors ): ?string {
|
|
if ( null === $amount_with_currency ) {
|
|
return null;
|
|
}
|
|
|
|
// Amount with decimal separator
|
|
$amount = $amount_with_currency['amount'] ?? '';
|
|
$currency = $amount_with_currency['currency'] ?? '';
|
|
if ( ! is_numeric( $amount ) ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CREATE_FAILURE, sprintf( 'Invalid amount string: %s', $amount ) );
|
|
return null;
|
|
}
|
|
|
|
$woocommerce_currency = get_woocommerce_currency();
|
|
if ( strtolower( $currency ) !== strtolower( $woocommerce_currency ) ) {
|
|
$errors[] = self::get_error_response_data( self::ERROR_OFFER_CREATE_FAILURE, sprintf( 'Provided currency (%s) does not match store currency (%s)', $currency, $woocommerce_currency ) );
|
|
return null;
|
|
}
|
|
|
|
return $amount;
|
|
}
|
|
}
|