Skip to content

Commit

Permalink
Merge pull request #2905 from woocommerce/PCP-2941_change-hardcoded-A…
Browse files Browse the repository at this point in the history
…ddress-Match-and-Postal-Match-to-Matched-details-on-CVV-response

Change hardcoded address match and postal match to matched details on cvv response
  • Loading branch information
InpsydeNiklas authored Dec 23, 2024
2 parents 26abc74 + ae27521 commit dcbf318
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 52 deletions.
116 changes: 102 additions & 14 deletions modules/ppcp-api-client/src/Entity/FraudProcessorResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,44 @@ class FraudProcessorResponse {
/**
* The AVS response code.
*
* @var string|null
* @var string
*/
protected $avs_code;
protected string $avs_code;

/**
* The CVV response code.
*
* @var string|null
* @var string
*/
protected $cvv_code;
protected string $cvv2_code;

/**
* FraudProcessorResponse constructor.
*
* @param string|null $avs_code The AVS response code.
* @param string|null $cvv_code The CVV response code.
* @param string|null $cvv2_code The CVV response code.
*/
public function __construct( ?string $avs_code, ?string $cvv_code ) {
$this->avs_code = $avs_code;
$this->cvv_code = $cvv_code;
public function __construct( ?string $avs_code, ?string $cvv2_code ) {
$this->avs_code = (string) $avs_code;
$this->cvv2_code = (string) $cvv2_code;
}

/**
* Returns the AVS response code.
*
* @return string|null
* @return string
*/
public function avs_code(): ?string {
public function avs_code(): string {
return $this->avs_code;
}

/**
* Returns the CVV response code.
*
* @return string|null
* @return string
*/
public function cvv_code(): ?string {
return $this->cvv_code;
public function cvv_code(): string {
return $this->cvv2_code;
}

/**
Expand All @@ -64,11 +64,99 @@ public function cvv_code(): ?string {
*/
public function to_array(): array {
return array(
'avs_code' => $this->avs_code() ?: '',
'avs_code' => $this->avs_code(),
'cvv2_code' => $this->cvv_code(),
// For backwards compatibility.
'address_match' => $this->avs_code() === 'M' ? 'Y' : 'N',
'postal_match' => $this->avs_code() === 'M' ? 'Y' : 'N',
'cvv_match' => $this->cvv_code() === 'M' ? 'Y' : 'N',
);
}

/**
* Retrieves the AVS (Address Verification System) code messages based on the AVS response code.
*
* Provides human-readable descriptions for various AVS response codes
* and returns the corresponding message for the given code.
*
* @return string The AVS response code message. If the code is not found, an error message is returned.
*/
public function get_avs_code_message(): string {
if ( ! $this->avs_code() ) {
return '';
}
$messages = array(
/* Visa, Mastercard, Discover, American Express */
'A' => 'A: Address - Address only (no ZIP code)',
'B' => 'B: International "A" - Address only (no ZIP code)',
'C' => 'C: International "N" - None. The transaction is declined.',
'D' => 'D: International "X" - Address and Postal Code',
'E' => 'E: Not allowed for MOTO (Internet/Phone) transactions - Not applicable. The transaction is declined.',
'F' => 'F: UK-specific "X" - Address and Postal Code',
'G' => 'G: Global Unavailable - Not applicable',
'I' => 'I: International Unavailable - Not applicable',
'M' => 'M: Address - Address and Postal Code',
'N' => 'N: No - None. The transaction is declined.',
'P' => 'P: Postal (International "Z") - Postal Code only (no Address)',
'R' => 'R: Retry - Not applicable',
'S' => 'S: Service not Supported - Not applicable',
'U' => 'U: Unavailable / Address not checked, or acquirer had no response. Service not available.',
'W' => 'W: Whole ZIP - Nine-digit ZIP code (no Address)',
'X' => 'X: Exact match - Address and nine-digit ZIP code)',
'Y' => 'Y: Yes - Address and five-digit ZIP',
'Z' => 'Z: ZIP - Five-digit ZIP code (no Address)',
/* Maestro */
'0' => '0: All the address information matched.',
'1' => '1: None of the address information matched. The transaction is declined.',
'2' => '2: Part of the address information matched.',
'3' => '3: The merchant did not provide AVS information. Not processed.',
'4' => '4: Address not checked, or acquirer had no response. Service not available.',
);

/**
* Psalm suppress
*
* @psalm-suppress PossiblyNullArrayOffset
* @psalm-suppress PossiblyNullArgument
*/
return $messages[ $this->avs_code() ] ?? sprintf( '%s: Error', $this->avs_code() );
}

/**
* Retrieves the CVV2 code message based on the CVV code provided.
*
* This method maps CVV response codes to their corresponding descriptive messages.
*
* @return string The descriptive message corresponding to the CVV2 code, or a formatted error message if the code is unrecognized.
*/
public function get_cvv2_code_message(): string {
if ( ! $this->cvv_code() ) {
return '';
}
$messages = array(
/* Visa, Mastercard, Discover, American Express */
'E' => 'E: Error - Unrecognized or Unknown response',
'I' => 'I: Invalid or Null',
'M' => 'M: Match or CSC',
'N' => 'N: No match',
'P' => 'P: Not processed',
'S' => 'S: Service not supported',
'U' => 'U: Unknown - Issuer is not certified',
'X' => 'X: No response / Service not available',
/* Maestro */
'0' => '0: Matched CVV2',
'1' => '1: No match',
'2' => '2: The merchant has not implemented CVV2 code handling',
'3' => '3: Merchant has indicated that CVV2 is not present on card',
'4' => '4: Service not available',
);

/**
* Psalm suppress
*
* @psalm-suppress PossiblyNullArrayOffset
* @psalm-suppress PossiblyNullArgument
*/
return $messages[ $this->cvv_code() ] ?? sprintf( '%s: Error', $this->cvv_code() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,52 +96,35 @@ protected function handle_fraud( FraudProcessorResponse $fraud, Order $order, WC
return;
}

$fraud_responses = $fraud->to_array();
$card_brand = $payment_source->properties()->brand ?? __( 'N/A', 'woocommerce-paypal-payments' );
$card_last_digits = $payment_source->properties()->last_digits ?? __( 'N/A', 'woocommerce-paypal-payments' );

$avs_response_order_note_title = __( 'Address Verification Result', 'woocommerce-paypal-payments' );
$response_order_note_title = __( 'PayPal Advanced Card Processing Verification:', 'woocommerce-paypal-payments' );
/* translators: %1$s is AVS order note title, %2$s is AVS order note result markup */
$avs_response_order_note_format = __( '%1$s %2$s', 'woocommerce-paypal-payments' );
$avs_response_order_note_result_format = '<ul class="ppcp_avs_result">
<li>%1$s</li>
<ul class="ppcp_avs_result_inner">
<li>%2$s</li>
<li>%3$s</li>
</ul>
<li>%4$s</li>
<li>%5$s</li>
</ul>';
$avs_response_order_note_result = sprintf(
$avs_response_order_note_result_format,
/* translators: %s is fraud AVS code */
sprintf( __( 'AVS: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['avs_code'] ) ),
/* translators: %s is fraud AVS address match */
sprintf( __( 'Address Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['address_match'] ) ),
/* translators: %s is fraud AVS postal match */
sprintf( __( 'Postal Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['postal_match'] ) ),
/* translators: %s is card brand */
sprintf( __( 'Card Brand: %s', 'woocommerce-paypal-payments' ), esc_html( $card_brand ) ),
/* translators: %s card last digits */
sprintf( __( 'Card Last Digits: %s', 'woocommerce-paypal-payments' ), esc_html( $card_last_digits ) )
$response_order_note_format = __( '%1$s %2$s', 'woocommerce-paypal-payments' );
$response_order_note_result_format = '<ul class="ppcp_avs_cvv_result">
<li>%1$s</li>
<li>%2$s</li>
<li>%3$s</li>
</ul>';
$response_order_note_result = sprintf(
$response_order_note_result_format,
/* translators: %1$s is card brand and %2$s card last 4 digits */
sprintf( __( 'Card: %1$s (%2$s)', 'woocommerce-paypal-payments' ), $card_brand, $card_last_digits ),
/* translators: %s is fraud AVS message */
sprintf( __( 'AVS: %s', 'woocommerce-paypal-payments' ), $fraud->get_avs_code_message() ),
/* translators: %s is fraud CVV message */
sprintf( __( 'CVV: %s', 'woocommerce-paypal-payments' ), $fraud->get_cvv2_code_message() ),
);
$avs_response_order_note = sprintf(
$avs_response_order_note_format,
esc_html( $avs_response_order_note_title ),
wp_kses_post( $avs_response_order_note_result )
);
$wc_order->add_order_note( $avs_response_order_note );

$cvv_response_order_note_format = '<ul class="ppcp_cvv_result"><li>%1$s</li></ul>';
$cvv_response_order_note = sprintf(
$cvv_response_order_note_format,
/* translators: %s is fraud CVV match */
sprintf( __( 'CVV2 Match: %s', 'woocommerce-paypal-payments' ), esc_html( $fraud_responses['cvv_match'] ) )
$response_order_note = sprintf(
$response_order_note_format,
esc_html( $response_order_note_title ),
wp_kses_post( $response_order_note_result )
);
$wc_order->add_order_note( $cvv_response_order_note );
$wc_order->add_order_note( $response_order_note );

$meta_details = array_merge(
$fraud_responses,
$fraud->to_array(),
array(
'card_brand' => $card_brand,
'card_last_digits' => $card_last_digits,
Expand Down

0 comments on commit dcbf318

Please sign in to comment.