PluginProbe
Tiered Pricing Table for WooCommerce / 8.0.2
Tiered Pricing Table for WooCommerce v8.0.2
8.0.2 7.1.7 7.1.5 7.1.4 7.1.1 6.5.0 6.4.0 6.1.0 trunk 1.0 1.1 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0 2.3.1 2.3.2 2.3.3 All 91 releases
tier-pricing-table / src / Addons / NonLoggedInUsers / Wholesale / Models / WholesaleApplication.php

WholesaleApplication.php in Tiered Pricing Table for WooCommerce 8.0.2, at src/Addons/NonLoggedInUsers/Wholesale/Models/WholesaleApplication.php

322 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php namespace TierPricingTable\Addons\NonLoggedInUsers\Wholesale\Models;
2
3 use TierPricingTable\Addons\NonLoggedInUsers\Wholesale\CPT\ApplicationCPT;
4 use TierPricingTable\Addons\NonLoggedInUsers\Wholesale\Settings\Settings;
5 use WP_Post;
6 use WP_User;
7
8 /**
9 * A wholesale account application, stored as a post of the tpt-wholesale-application type.
10 * The post status is the application status; everything else is post meta.
11 */
12 class WholesaleApplication {
13
14 const STATUS_PENDING = 'tpt-pending';
15 const STATUS_APPROVED = 'tpt-approved';
16 const STATUS_REJECTED = 'tpt-rejected';
17
18 const USER_META_STATUS = '_tpt_wholesale_status';
19 const USER_META_APPLICATION = '_tpt_wholesale_application';
20
21 /** Values of the fields the store owner added to the form: key => [ label, type, value ]. */
22 const META_CUSTOM_FIELDS = '_custom_fields';
23
24 /** Meta keys of the stored fields. */
25 const FIELDS = array(
26 'user_id' => '_user_id',
27 'email' => '_email',
28 'first_name' => '_first_name',
29 'last_name' => '_last_name',
30 'company' => '_company',
31 'phone' => '_phone',
32 'tax_id' => '_tax_id',
33 'website' => '_website',
34 'message' => '_message',
35 'requested_role' => '_requested_role',
36 'decided_by' => '_decided_by',
37 'decided_at' => '_decided_at',
38 'rejection_reason' => '_rejection_reason',
39 );
40
41 protected int $id = 0;
42
43 protected string $status = self::STATUS_PENDING;
44
45 protected string $date = '';
46
47 protected array $data = array();
48
49 /**
50 * @param int|WP_Post $post
51 */
52 public function __construct( $post = 0 ) {
53 $post = $post instanceof WP_Post ? $post : ( $post ? get_post( (int) $post ) : null );
54
55 if ( $post && ApplicationCPT::POST_TYPE === $post->post_type ) {
56 $this->id = (int) $post->ID;
57 $this->status = (string) $post->post_status;
58 $this->date = (string) $post->post_date;
59
60 foreach ( self::FIELDS as $prop => $metaKey ) {
61 $this->data[ $prop ] = (string) get_post_meta( $this->id, $metaKey, true );
62 }
63 }
64 }
65
66 public static function get( int $id ): ?self {
67 $application = new self( $id );
68
69 return $application->getId() ? $application : null;
70 }
71
72 /**
73 * The latest application of a user, whatever its status.
74 */
75 public static function findForUser( int $userId ): ?self {
76 if ( ! $userId ) {
77 return null;
78 }
79
80 $applicationId = (int) get_user_meta( $userId, self::USER_META_APPLICATION, true );
81
82 if ( $applicationId ) {
83 $application = self::get( $applicationId );
84
85 if ( $application ) {
86 return $application;
87 }
88 }
89
90 $posts = get_posts( array(
91 'post_type' => ApplicationCPT::POST_TYPE,
92 'post_status' => self::getStatuses(),
93 'posts_per_page' => 1,
94 'orderby' => 'date',
95 'order' => 'DESC',
96 'meta_key' => self::FIELDS['user_id'],
97 'meta_value' => $userId,
98 'fields' => 'ids',
99 ) );
100
101 return $posts ? self::get( (int) $posts[0] ) : null;
102 }
103
104 public static function getStatuses(): array {
105 return array( self::STATUS_PENDING, self::STATUS_APPROVED, self::STATUS_REJECTED );
106 }
107
108 public static function getStatusLabels(): array {
109 return array(
110 self::STATUS_PENDING => __( 'Pending', 'tier-pricing-table' ),
111 self::STATUS_APPROVED => __( 'Approved', 'tier-pricing-table' ),
112 self::STATUS_REJECTED => __( 'Rejected', 'tier-pricing-table' ),
113 );
114 }
115
116 public static function countPending(): int {
117 $counts = wp_count_posts( ApplicationCPT::POST_TYPE );
118
119 return (int) ( $counts->{self::STATUS_PENDING} ?? 0 );
120 }
121
122 /**
123 * Creates the post for a validated application.
124 *
125 * @param array $data keys of self::FIELDS
126 *
127 * @return self|null
128 */
129 public static function create( array $data ): ?self {
130 $title = trim( ( $data['company'] ?? '' ) ?: trim( ( $data['first_name'] ?? '' ) . ' ' . ( $data['last_name'] ?? '' ) ) );
131
132 $postId = wp_insert_post( array(
133 'post_type' => ApplicationCPT::POST_TYPE,
134 'post_status' => self::STATUS_PENDING,
135 'post_title' => $title ?: (string) ( $data['email'] ?? '' ),
136 ), true );
137
138 if ( is_wp_error( $postId ) || ! $postId ) {
139 return null;
140 }
141
142 foreach ( self::FIELDS as $prop => $metaKey ) {
143 if ( array_key_exists( $prop, $data ) ) {
144 update_post_meta( $postId, $metaKey, $data[ $prop ] );
145 }
146 }
147
148 if ( ! empty( $data['custom_fields'] ) && is_array( $data['custom_fields'] ) ) {
149 update_post_meta( $postId, self::META_CUSTOM_FIELDS, $data['custom_fields'] );
150 }
151
152 if ( ! empty( $data['user_id'] ) ) {
153 update_user_meta( (int) $data['user_id'], self::USER_META_APPLICATION, $postId );
154 update_user_meta( (int) $data['user_id'], self::USER_META_STATUS, self::STATUS_PENDING );
155 }
156
157 return self::get( (int) $postId );
158 }
159
160 public function getId(): int {
161 return $this->id;
162 }
163
164 public function getStatus(): string {
165 return $this->status;
166 }
167
168 public function getStatusLabel(): string {
169 return self::getStatusLabels()[ $this->status ] ?? $this->status;
170 }
171
172 public function isPending(): bool {
173 return self::STATUS_PENDING === $this->status;
174 }
175
176 public function isApproved(): bool {
177 return self::STATUS_APPROVED === $this->status;
178 }
179
180 public function isRejected(): bool {
181 return self::STATUS_REJECTED === $this->status;
182 }
183
184 public function getDate(): string {
185 return $this->date;
186 }
187
188 public function getField( string $prop ): string {
189 return (string) ( $this->data[ $prop ] ?? '' );
190 }
191
192 public function getUserId(): int {
193 return (int) $this->getField( 'user_id' );
194 }
195
196 public function getUser(): ?WP_User {
197 $user = $this->getUserId() ? get_user_by( 'id', $this->getUserId() ) : false;
198
199 return $user instanceof WP_User ? $user : null;
200 }
201
202 public function getEmail(): string {
203 return $this->getField( 'email' );
204 }
205
206 public function getName(): string {
207 return trim( $this->getField( 'first_name' ) . ' ' . $this->getField( 'last_name' ) );
208 }
209
210 public function getCompany(): string {
211 return $this->getField( 'company' );
212 }
213
214 public function getRequestedRole(): string {
215 return $this->getField( 'requested_role' );
216 }
217
218 public function getRejectionReason(): string {
219 return $this->getField( 'rejection_reason' );
220 }
221
222 /**
223 * @return array<string, array{label: string, type: string, value: string}>
224 */
225 public function getCustomFields(): array {
226 $fields = $this->id ? get_post_meta( $this->id, self::META_CUSTOM_FIELDS, true ) : array();
227
228 return is_array( $fields ) ? $fields : array();
229 }
230
231 /**
232 * Moves the application to a new status and records who decided and when.
233 */
234 public function setStatus( string $status, int $decidedBy = 0, string $reason = '' ): bool {
235 if ( ! in_array( $status, self::getStatuses(), true ) || ! $this->id ) {
236 return false;
237 }
238
239 $updated = wp_update_post( array( 'ID' => $this->id, 'post_status' => $status ), true );
240
241 if ( is_wp_error( $updated ) ) {
242 return false;
243 }
244
245 $this->status = $status;
246
247 if ( self::STATUS_PENDING !== $status ) {
248 $this->setMeta( 'decided_by', (string) $decidedBy );
249 $this->setMeta( 'decided_at', current_time( 'mysql' ) );
250 }
251
252 if ( self::STATUS_REJECTED === $status ) {
253 $this->setMeta( 'rejection_reason', $reason );
254 }
255
256 if ( $this->getUserId() ) {
257 update_user_meta( $this->getUserId(), self::USER_META_STATUS, $status );
258 update_user_meta( $this->getUserId(), self::USER_META_APPLICATION, $this->id );
259 }
260
261 return true;
262 }
263
264 public function setMeta( string $prop, string $value ) {
265 if ( isset( self::FIELDS[ $prop ] ) && $this->id ) {
266 update_post_meta( $this->id, self::FIELDS[ $prop ], $value );
267 $this->data[ $prop ] = $value;
268 }
269 }
270
271 /**
272 * Label/value pairs of the business details the applicant filled in.
273 *
274 * @return array<string, string> label => value
275 */
276 public function getDetails(): array {
277 $details = array(
278 __( 'Name', 'tier-pricing-table' ) => $this->getName(),
279 __( 'E-mail', 'tier-pricing-table' ) => $this->getEmail(),
280 );
281
282 // the labels the store owner gave the recognised fields, with the stock labels as fallback
283 $labels = array(
284 'company' => __( 'Company', 'tier-pricing-table' ),
285 'phone' => __( 'Phone', 'tier-pricing-table' ),
286 'tax_id' => __( 'Tax / VAT ID', 'tier-pricing-table' ),
287 'website' => __( 'Website', 'tier-pricing-table' ),
288 'message' => __( 'Message', 'tier-pricing-table' ),
289 );
290
291 foreach ( Settings::getFormFields() as $field ) {
292 if ( isset( $labels[ $field['key'] ] ) && '' !== $field['label'] ) {
293 $labels[ $field['key'] ] = $field['label'];
294 }
295 }
296
297 foreach ( $labels as $prop => $label ) {
298 if ( '' !== $this->getField( $prop ) ) {
299 $details[ $label ] = $this->getField( $prop );
300 }
301 }
302
303 foreach ( $this->getCustomFields() as $custom ) {
304 $value = (string) ( $custom['value'] ?? '' );
305
306 if ( 'checkbox' === ( $custom['type'] ?? '' ) ) {
307 $value = '1' === $value ? __( 'Yes', 'tier-pricing-table' ) : __( 'No', 'tier-pricing-table' );
308 }
309
310 if ( '' !== $value ) {
311 $details[ (string) ( $custom['label'] ?? '' ) ] = $value;
312 }
313 }
314
315 return $details;
316 }
317
318 public function getAdminUrl(): string {
319 return $this->id ? (string) get_edit_post_link( $this->id, 'raw' ) : '';
320 }
321 }
322