Files
2026-04-28 15:13:50 +02:00

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;
}
}