Initial commit.
This commit is contained in:
@@ -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 ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user