Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
68.63% covered (warning)
68.63%
35 / 51
54.55% covered (warning)
54.55%
6 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Sales_By_Coupon_Controller
68.00% covered (warning)
68.00%
34 / 50
54.55% covered (warning)
54.55%
6 / 11
14.96
0.00% covered (danger)
0.00%
0 / 1
 get_report_key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_report_label
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_data_endpoint
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get_column_headers
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 format_row_for_csv
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 get_default_values
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 get_additional_params
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 get_fields
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 get_matching_field
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_identifying_fields
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_empty_row_check_field
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * REST API Reports Sales by Coupon controller class.
4 *
5 * @package Automattic\Jetpack\PremiumAnalytics\Reports\Export\Exports
6 */
7
8declare( strict_types=1 );
9
10namespace Automattic\Jetpack\PremiumAnalytics\Reports\Export\Exports;
11
12defined( 'ABSPATH' ) || exit;
13
14use Automattic\Jetpack\PremiumAnalytics\Reports\Export\Abstract_Csv_Report_Controller;
15
16/**
17 * Sales by Coupon CSV Export Controller.
18 *
19 * Handles CSV exports for the Sales by Coupon report.
20 * Note: This is a ranked list report, not a time-series report.
21 * Comparison mode is supported using ID-based merging (matching by coupon_code).
22 *
23 * @since $$next-version$$
24 */
25class Sales_By_Coupon_Controller extends Abstract_Csv_Report_Controller {
26
27    /**
28     * Get the report key for this controller.
29     *
30     * @return string The report key.
31     */
32    public function get_report_key(): string {
33        return 'salesbycoupon';
34    }
35
36    /**
37     * Get the report label for this controller.
38     *
39     * @return string The report label.
40     */
41    public function get_report_label(): string {
42        return __( 'Sales by Coupon', 'jetpack-premium-analytics' );
43    }
44
45    /**
46     * Get the data endpoint for this controller.
47     *
48     * @return string The data endpoint.
49     */
50    public function get_data_endpoint(): string {
51        return 'reports/coupons';
52    }
53
54    /**
55     * Get the column headers for this controller.
56     *
57     * @param string|null $interval Optional time interval for dynamic headers.
58     * @return array The column headers.
59     */
60    public function get_column_headers( ?string $interval = null ): array { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature required by the report controller interface.
61        return array(
62            'coupon_code'         => __( 'Coupon Code', 'jetpack-premium-analytics' ),
63            'orders_count'        => __( 'Orders with coupon', 'jetpack-premium-analytics' ),
64            'net_total'           => __( 'Net sales', 'jetpack-premium-analytics' ),
65            'discount_amount'     => __( 'Discount amount', 'jetpack-premium-analytics' ),
66            'average_order_value' => __( 'Average order value with coupon', 'jetpack-premium-analytics' ),
67            'new_customers'       => __( 'New customers', 'jetpack-premium-analytics' ),
68            'returning_customers' => __( 'Returning customers', 'jetpack-premium-analytics' ),
69        );
70    }
71
72    /**
73     * Format a row for CSV export.
74     *
75     * @param array       $item     The row data.
76     * @param string|null $interval Optional time interval for formatting.
77     * @return array The formatted row.
78     */
79    public function format_row_for_csv( array $item, ?string $interval = null ): array { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Signature required by the report controller interface.
80        $defaults = $this->get_default_values();
81
82        $total_customers     = $item['total_customers'] ?? $defaults['total_customers'];
83        $new_customers       = $item['new_customers'] ?? $defaults['new_customers'];
84        $returning_customers = max( $total_customers - $new_customers, 0 );
85
86        return array(
87            'coupon_code'         => $item['coupon_code'] ?? $defaults['coupon_code'],
88            'orders_count'        => $item['orders_count'] ?? $defaults['orders_count'],
89            'net_total'           => self::format_amount( $item['net_total'] ?? $defaults['net_total'] ),
90            'discount_amount'     => self::format_amount( $item['discount_amount'] ?? $defaults['discount_amount'] ),
91            'average_order_value' => self::format_amount( $item['average_order_value'] ?? $defaults['average_order_value'] ),
92            'new_customers'       => $new_customers,
93            'returning_customers' => $returning_customers,
94        );
95    }
96
97    /**
98     * Get default values for missing data fields.
99     *
100     * @return array Array of field_name => default_value pairs.
101     */
102    public function get_default_values(): array {
103        return array(
104            'coupon_code'         => '',
105            'orders_count'        => 0,
106            'net_total'           => 0,
107            'discount_amount'     => 0,
108            'average_order_value' => 0,
109            'new_customers'       => 0,
110            'total_customers'     => 0,
111        );
112    }
113
114    /**
115     * Get additional request parameters for data fetching.
116     *
117     * Sets orderby to orders_count.
118     *
119     * @return array Additional parameters to include in data requests.
120     */
121    public function get_additional_params(): array {
122        return array(
123            'date_type' => self::DEFAULT_DATE_TYPE,
124            'orderby'   => 'orders_count',
125        );
126    }
127
128    /**
129     * Get the list of API fields needed for this report.
130     *
131     * @return array
132     */
133    public function get_fields(): array {
134        return array(
135            'coupon_code',
136            'orders_count',
137            'net_total',
138            'discount_amount',
139            'average_order_value',
140            'new_customers',
141            'total_customers',
142        );
143    }
144
145    /**
146     * Get the matching field for comparison data alignment.
147     *
148     * Uses coupon_code for ID-based merging in this ranked report.
149     *
150     * @return string|null
151     */
152    public function get_matching_field(): ?string {
153        return 'coupon_code';
154    }
155
156    /**
157     * Get the identifying fields that should be preserved in comparison data.
158     *
159     * @return array
160     */
161    public function get_identifying_fields(): array {
162        return array( 'coupon_code' );
163    }
164
165    /**
166     * Get the field name(s) to check for emptiness when determining if a row should be skipped.
167     *
168     * @return array
169     */
170    public function get_empty_row_check_field() {
171        return array( 'coupon_code' );
172    }
173}