Initial commit.

This commit is contained in:
2025-11-24 21:33:55 +00:00
parent 14b7ade051
commit d6e9d316bc
8974 changed files with 1423277 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
<?php
/**
* Class WC_Payments_In_Person_Payment_Print_Receipt_Service
*
* @package WooCommerce\Payments
*/
defined( 'ABSPATH' ) || exit;
/**
* Class handling in person payments receipts.
*/
class WC_Payments_In_Person_Payments_Receipts_Service {
/**
* Renders the receipt template.
*
* @param array $settings Merchant settings.
* @param WC_Order $order Order instance.
* @param array $charge Charge data.
*
* @return string
*/
public function get_receipt_markup( array $settings, WC_Order $order, array $charge ): string {
$this->validate_settings( $settings );
$this->validate_charge( $charge );
if ( $order instanceof WC_Payments_Printed_Receipt_Sample_Order ) {
$order_data = $order->get_data();
$line_items_data = $order_data['line_items'];
} else {
$order_data = [
'id' => $order->get_id(),
'currency' => $order->get_currency(),
'subtotal' => $order->get_subtotal(),
'line_items' => $order->get_items(),
'coupon_lines' => $order->get_items( 'coupon' ),
'tax_lines' => $order->get_items( 'tax' ),
'total' => $order->get_total(),
'shipping_tax' => $order->get_shipping_methods() ? $order->get_shipping_total() : 0,
'total_fees' => $order->get_total_fees(),
];
$line_items_data = $this->format_line_items( $order_data );
}
ob_start();
wc_get_template(
'html-in-person-payment-receipt.php',
[
'amount_captured' => $charge['amount_captured'] / 100,
'coupon_lines' => $order_data['coupon_lines'] ?? [],
'branding_logo' => $settings['branding_logo'] ?? [],
'business_name' => $settings['business_name'],
'line_items' => $line_items_data,
'order' => $order_data,
'payment_method_details' => $charge['payment_method_details']['card_present'],
'receipt' => $charge['payment_method_details']['card_present']['receipt'],
'support_address' => $settings['support_info']['address'],
'support_email' => $settings['support_info']['email'],
'support_phone' => $settings['support_info']['phone'],
'tax_lines' => $order_data['tax_lines'] ?? [],
],
'',
__DIR__ . '/templates/'
);
return ob_get_clean();
}
/**
* Send card reader receipt to customer by email
*
* @param WC_Order $order the order.
* @param array $merchant_settings The merchant settings.
* @param array $charge the charge.
* @return void
*/
public function send_customer_ipp_receipt_email( WC_Order $order, array $merchant_settings, array $charge ) {
$email_receipt = WC()->mailer()->get_emails()['WC_Payments_Email_IPP_Receipt'];
if ( $email_receipt instanceof WC_Payments_Email_IPP_Receipt ) {
$email_receipt->trigger( $order, $merchant_settings, $charge );
}
}
/**
* Format line items
*
* @param array $order the order.
* @return array
*/
private function format_line_items( array $order ): array {
$line_items_data = [];
foreach ( $order['line_items'] as $item ) {
$item_data = $item->get_data();
$item_data['product'] = $item->get_product()->get_data();
$line_items_data[] = $item_data;
}
return $line_items_data;
}
/**
* Validate settings
*
* @param array $settings Settings.
* @return void
* @throws \RuntimeException Error validating settings.
*/
private function validate_settings( array $settings ) {
if ( ! array_key_exists( 'business_name', $settings ) ) {
throw new \RuntimeException( 'Business name needs to be provided.' );
}
if ( empty( $settings['support_info'] ) || ! is_array( $settings['support_info'] ) ) {
throw new \RuntimeException( 'Support information needs to be provided.' );
}
$this->validate_required_fields(
[ 'address', 'email', 'phone' ],
$settings['support_info'],
'Error validating support information'
);
}
/**
* Validate charge information
*
* @param array $charge Charge info.
* @return void
* @throws \RuntimeException Error validating charge info.
*/
private function validate_charge( array $charge ) {
if ( ! array_key_exists( 'amount_captured', $charge ) ) {
throw new \RuntimeException( 'Captured amount needs to be provided.' );
}
if ( empty( $charge['payment_method_details']['card_present'] ) || ! is_array( $charge['payment_method_details']['card_present'] ) ) {
throw new \RuntimeException( 'Payment method details needs to be provided.' );
}
$this->validate_required_fields(
[ 'brand', 'last4', 'receipt' ],
$charge['payment_method_details']['card_present'],
'Error validating payment information'
);
$this->validate_required_fields(
[ 'application_preferred_name', 'dedicated_file_name', 'account_type' ],
$charge['payment_method_details']['card_present']['receipt'],
'Error validating receipt information'
);
}
/**
* Validate required field
*
* @param array $required_fields Required fields.
* @param array $data Data to validate.
* @param string $message Error message.
* @return void
* @throws \RuntimeException Error validating required fields.
*/
private function validate_required_fields( array $required_fields, array $data, string $message ) {
foreach ( $required_fields as $required_key ) {
if ( ! array_key_exists( $required_key, $data ) ) {
throw new \RuntimeException( esc_html( sprintf( '%s. Missing key: %s', $message, $required_key ) ) );
}
}
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Class WC_Payments_Printed_Receipt_Sample_Order
*
* @package WooCommerce\Payments
*/
use WCPay\Constants\Currency_Code;
defined( 'ABSPATH' ) || exit;
/**
* This class represents a sample order to be used when generating a preview of a printed receipt.
*
* @see WC_REST_Payments_Reader_Controller::preview_print_receipt
*/
class WC_Payments_Printed_Receipt_Sample_Order extends WC_Order {
const PREVIEW_RECEIPT_ORDER_DATA = [
'id' => '42',
'currency' => Currency_Code::UNITED_STATES_DOLLAR,
'subtotal' => 0,
'line_items' => [
[
'name' => 'Sample',
'quantity' => 1,
'subtotal' => 0,
'product' => [
'price' => 0,
'regular_price' => 1,
'id' => 'sample',
],
],
[
'name' => 'Sample',
'quantity' => 1,
'subtotal' => 0,
'product' => [
'price' => 0,
'regular_price' => 1,
'id' => 'sample',
],
],
],
'coupon_lines' => [
[
'code' => 'DISCOUNT',
'description' => 'sample',
'discount' => 0,
],
],
'tax_lines' => [
[
'rate_percent' => 0,
'tax_total' => '0',
],
],
'total' => 0,
'shipping_tax' => 0,
'total_fees' => 0,
];
/**
* __construct
*/
public function __construct() {
// noop.
}
/**
* Returns order data
*
* @return array
*/
public function get_data(): array {
return self::PREVIEW_RECEIPT_ORDER_DATA;
}
}

View File

@@ -0,0 +1,221 @@
<?php
/**
* In Person Payments Receipt Template
*
* @package WooCommerce\Payments
*/
/**
* Helper to generate markup to render a price.
*
* @param array $product The product to display.
* @param string $currency The currency to display.
* @return string
*/
function format_price_helper( array $product, string $currency ): string {
$active_price = $product['price'];
$regular_price = $product['regular_price'];
$has_discount = $active_price !== $regular_price;
if ( $has_discount ) {
return '<s>' . wc_price( $regular_price, [ 'currency' => $currency ] ) . '</s> ' . wc_price( $active_price, [ 'currency' => $currency ] );
}
return wc_price( $active_price, [ 'currency' => $currency ] );
}
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Print Receipt</title>
<style>
body {
margin: 0;
padding: 0;
border: 0;
}
.align-left {
text-align: left;
}
.align-right {
text-align: right;
}
.align-top {
vertical-align: top;
}
.receipt {
min-width: 130px;
max-width: 300px;
margin: 0 auto;
text-align: center;
font-family: SF Pro Text, sans-serif;
font-size: 10px;
}
.receipt-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 2px;
font-size: 10px;
}
.receipt__header .title {
font-size: 14px;
line-height: 17px;
margin-bottom: 12px;
margin-top: 12px;
font-weight: 700;
}
.receipt__header .store {
padding: 0 12px;
}
.receipt__header .store__address {
margin-top: 12px;
line-height: 2px;
}
.receipt__header .store__contact {
margin-top: 4px;
}
.receipt__header .order__title {
font-weight: 800;
}
.receipt__transaction {
line-height: 2px;
}
.branding-logo {
max-width: 250px;
margin: 20px auto;
}
#powered_by {
font-size: 7px;
padding-top: 5px;
}
</style>
</head>
<body>
<div class="receipt">
<div class="receipt__header">
<?php if ( ! empty( $branding_logo['content_type'] ) ) { ?>
<img class="branding-logo" src="data:<?php echo esc_html( $branding_logo['content_type'] ); ?>;base64,<?php echo esc_html( $branding_logo['file_content'] ); ?>" alt="<?php echo esc_html( $business_name ); ?>"/>
<?php } ?>
<h1 class="title"><?php echo esc_html( $business_name ); ?></h1>
<hr />
<div class="store">
<?php if ( $support_address ) { ?>
<div class="store__address">
<p><?php echo esc_html( $support_address['line1'] ); ?></p>
<p><?php echo esc_html( $support_address['line2'] ); ?></p>
<p><?php echo esc_html( implode( ' ', [ $support_address['city'], $support_address['state'], $support_address['postal_code'], $support_address['country'] ] ) ); ?></p>
<?php echo esc_html( gmdate( 'Y/m/d - H:iA' ) ); ?>
</div>
<?php } ?>
<p class="store__contact">
<?php echo esc_html( implode( ' ', [ $support_phone, $support_email ] ) ); ?>
</p>
</div>
<div class="order">
<p class="order__title"><?php printf( '%s %s', esc_html__( 'Order', 'woocommerce-payments' ), esc_html( $order['id'] ) ); ?></p>
</div>
</div>
<hr />
<div class="receipt__products">
<table class="receipt-table">
<?php foreach ( $line_items as $item ) { ?>
<tr>
<td class="align-left">
<div><?php echo esc_html( $item['name'] ); ?></div>
<div><?php echo esc_html( $item['quantity'] ); ?> @ <?php echo wp_kses( format_price_helper( $item['product'], $order['currency'] ), 'post' ); ?></div>
<div><?php printf( '%s: %s', esc_html__( 'SKU', 'woocommerce-payments' ), esc_html( $item['product']['id'] ) ); ?></div> <!-- TODO SKU or ID? -->
</td>
<td class="align-right align-top"><?php echo wp_kses( wc_price( $item['subtotal'], [ 'currency' => $order['currency'] ] ), 'post' ); ?></td>
</tr>
<?php } ?>
</table>
</div>
<hr />
<div class="receipt__subtotal">
<table class="receipt-table">
<tr>
<td class="align-left"><b><?php echo esc_html__( 'SUBTOTAL', 'woocommerce-payments' ); ?></b></td>
<td class="align-right"><b><?php echo wp_kses( wc_price( $order['subtotal'], [ 'currency' => $order['currency'] ] ), 'post' ); ?></b></td>
</tr>
<?php foreach ( $coupon_lines as $order_coupon ) { ?>
<tr>
<td class="align-left">
<div><?php printf( '%s: %s', esc_html__( 'Discount', 'woocommerce-payments' ), esc_html( $order_coupon['code'] ) ); ?></div>
<div><?php echo esc_html( $order_coupon['description'] ); ?></div>
</td>
<td class="align-right align-top"><?php echo wp_kses( wc_price( abs( $order_coupon['discount'] ) * -1, [ 'currency' => $order['currency'] ] ), 'post' ); ?></td>
</tr>
<?php } ?>
<?php if ( 0 < $order['total_fees'] ) : ?>
<tr>
<td class="align-left"><?php esc_html_e( 'Fees:', 'woocommerce-payments' ); ?></td>
<td class="align-right align-top">
<?php echo wp_kses( wc_price( $order['total_fees'], [ 'currency' => $order['currency'] ] ), 'post' ); ?>
</td>
</tr>
<?php endif; ?>
<?php if ( 0 < $order['shipping_tax'] ) : ?>
<tr>
<td class="align-left"><?php esc_html_e( 'Shipping:', 'woocommerce-payments' ); ?></td>
<td class="align-right align-top">
<?php echo wp_kses( wc_price( $order['shipping_tax'], [ 'currency' => $order['currency'] ] ), 'post' ); ?>
</td>
</tr>
<?php endif; ?>
<?php foreach ( $tax_lines as $tax_line ) { ?>
<tr>
<td class="align-left">
<div><?php echo esc_html__( 'Tax', 'woocommerce-payments' ); ?></div>
<div><?php echo esc_html( wc_round_tax_total( $tax_line['rate_percent'] ) ); ?>%</div>
</td>
<td class="align-right align-top"><?php echo wp_kses( wc_price( $tax_line['tax_total'] + $tax_line['shipping_tax_total'], [ 'currency' => $order['currency'] ] ), 'post' ); ?></td>
</tr>
<?php } ?>
<tr>
<td colspan="2" class="align-left"></td>
</tr>
<tr>
<td class="align-left"><b><?php echo esc_html__( 'TOTAL', 'woocommerce-payments' ); ?></b></td>
<td class="align-right"><b><?php echo wp_kses( wc_price( $order['total'], [ 'currency' => $order['currency'] ] ), 'post' ); ?></b></td>
</tr>
</table>
</div>
<hr />
<div class="receipt__amount-paid">
<table class="receipt-table">
<tr>
<td class="align-left"><b><?php echo esc_html__( 'AMOUNT PAID', 'woocommerce-payments' ); ?></b>:</td>
<td class="align-right"><b><?php echo wp_kses( wc_price( $amount_captured, [ 'currency' => $order['currency'] ] ), 'post' ); ?></b></td>
</tr>
<tr>
<td colspan="2" class="align-left"><?php echo esc_html( sprintf( '%s - %s', ucfirst( $payment_method_details['brand'] ), $payment_method_details['last4'] ) ); ?></td>
</tr>
</table>
</div>
<hr />
<div class="receipt__transaction">
<p id="application-preferred-name"><?php printf( '%s: %s', esc_html__( 'Application name', 'woocommerce-payments' ), esc_html( ucfirst( $receipt['application_preferred_name'] ) ) ); ?></p>
<p id="dedicated-file-name"><?php printf( '%s: %s', esc_html__( 'AID', 'woocommerce-payments' ), esc_html( ucfirst( $receipt['dedicated_file_name'] ) ) ); ?></p>
<p id="account_type"><?php printf( '%s: %s', esc_html__( 'Account Type', 'woocommerce-payments' ), esc_html( ucfirst( $receipt['account_type'] ) ) ); ?></p>
<p id="powered_by"><?php echo esc_html__( 'Powered by WooCommerce', 'woocommerce-payments' ); ?></p>
</div>
</div>
</body>
</html>