PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.7.2
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.7.2
3.0.3 3.0.2 3.0.1 trunk 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.3.0 2.3.1 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.91 2.7.92 2.7.93 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0
commercebird / includes / classes / zoho-inventory / class-import-price-list.php
commercebird / includes / classes / zoho-inventory Last commit date
class-cmbird-categories-zi.php 8 months ago class-cmbird-image-zi.php 6 months ago class-import-items.php 6 months ago class-import-price-list.php 11 months ago class-multi-currency.php 8 months ago class-order-sync.php 6 months ago class-product.php 6 months ago class-users-contact.php 6 months ago index.php 1 year ago
class-import-price-list.php
363 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 /**
8 * Class CMBIRD_Pricelist_ZI
9 *
10 * Handles importing Zoho price lists into WooCommerce and B2B plugins.
11 */
12 class CMBIRD_Pricelist_ZI {
13 use CommerceBird\Admin\Traits\LogWriter;
14
15 /**
16 * Configuration array containing Zoho Inventory API details.
17 *
18 * @var array
19 */
20 private array $config;
21
22 /**
23 * Class constructor.
24 *
25 * Retrieves Zoho Inventory connection configuration options for OID and API URL.
26 */
27 public function __construct() {
28 $this->config = array(
29 'ProductZI' => array(
30 'OID' => get_option( 'cmbird_zoho_inventory_oid' ),
31 'APIURL' => get_option( 'cmbird_zoho_inventory_url' ),
32 ),
33 );
34 }
35
36 /**
37 * Get all Zoho price list
38 * Example response:
39 * {
40 * "currency_code": Code based on currency,
41 * "currency_id": The currenct id of the currency,
42 * "decimal_place": Decimal place for pricebook.,
43 * "description": Description about the pricebook,
44 * "is_default": To check the default pricebook.Allowed values: true,false,
45 * "is_increase": Mark up or Mark down to discounts.Allowed values: true,false,
46 * "name": Name of the pricebook,
47 * "percentage": About percentage of discounts,
48 * "pricebook_id": Unique ID generated by server for the price book,
49 * "pricebook_items": [
50 * {
51 * "item_id": Unique ID generated by server for Item,
52 * "pricebook_rate": Rate of the price book for the Items,
53 * "pricebook_item_id": Unique ID generated by the server for each pricebook line item
54 * }
55 * ],
56 * "pricebook_type": Type of the pricebook.Allowed values: per_item,fixed_percentage,
57 * "rounding_type": Type of the rounding.Allowed values: no_rounding,round_to_dollor,round_to_dollar_minus_01,round_to_half_dollar,round_to_half_dollar_minus_01,
58 * "sales_or_purchase_type": Whether its sales or purchase type.Allowed values: sales,purchases,
59 * "status": Status of the price book
60 * }
61 *
62 * @return array of price list
63 */
64 public function zi_get_all_pricelist(): array {
65 $in_cache = get_transient( 'zoho_pricelist' );
66 if ( $in_cache ) {
67 return $in_cache;
68 }
69
70 $url = $this->config['ProductZI']['APIURL'] . 'inventory/v1/pricebooks?organization_id=' . $this->config['ProductZI']['OID'];
71 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
72 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
73
74 if ( isset( $json->pricebooks ) ) {
75 set_transient( 'zoho_pricelist', $json->pricebooks, MINUTE_IN_SECONDS );
76
77 return $json->pricebooks;
78 }
79
80 return array();
81 }
82
83 /**
84 * Save pricelist function to update prices and discounts for user roles.
85 *
86 * @param array $post The post-data containing user role and price information.
87 * Example:
88 * {
89 * "zoho_inventory_pricelist": Zoho inventory pricelist id
90 * "wp_user_role": WordPress user role
91 * }
92 */
93 public function save_price_list( array $post ): bool {
94 if ( class_exists( 'Addify_B2B_Plugin' ) ) {
95 $success = $this->addify_b2b( $post['zoho_inventory_pricelist'], $post['wp_user_role'] );
96 } elseif ( class_exists( 'WooCommerceB2B' ) ) {
97 $success = $this->wc_b2b( $post['wcb2b'] );
98 }
99 return $success;
100 }
101
102 /**
103 * Get a Zoho price list based on a price book id
104 *
105 * @param int $pricebook_id pricebook id.
106 *
107 * @return array of price list
108 */
109 private function get_zoho_pricebook( int $pricebook_id ): array {
110 $in_cache = get_transient( 'zoho_pricelist_' . $pricebook_id );
111 if ( $in_cache ) {
112 return $in_cache;
113 }
114 $url = $this->config['ProductZI']['APIURL'] . 'inventory/v1/pricebooks/' . $pricebook_id . '?organization_id=' . $this->config['ProductZI']['OID'];
115 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
116 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
117 if ( is_object( $json ) && property_exists( $json, 'pricebook' ) ) {
118 $json = json_decode( wp_json_encode( $json->pricebook ), true );
119 set_transient( 'zoho_pricelist_' . $pricebook_id, $json, DAY_IN_SECONDS );
120 update_option( 'cmbird_zoho_pricelist_id', $pricebook_id );
121
122 return $json;
123 }
124
125 return array();
126 }
127
128 /**
129 * Get published product ids, based on zi_item_id meta-key
130 *
131 * @return array
132 */
133 private function get_zoho_products(): array {
134 $in_cache = get_transient( 'zoho_products' );
135 if ( $in_cache ) {
136 return $in_cache;
137 }
138 global $wpdb;
139
140 $ids = $wpdb->get_results(
141 "SELECT p.ID AS id, pm.meta_value AS zi_item_id
142 FROM {$wpdb->postmeta} pm
143 INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
144 WHERE pm.meta_key = 'zi_item_id'
145 AND p.post_type in ('product', 'product_variation')
146 AND p.post_status = 'publish'
147 AND pm.meta_value != ''",
148 ARRAY_A
149 );
150
151 $plist = wp_list_pluck( $ids, 'id', 'zi_item_id' );
152 ksort( $plist );
153 set_transient( 'zoho_products', $plist, DAY_IN_SECONDS );
154
155 return $plist;
156 }
157
158 /**
159 * Support For Addify B2B
160 *
161 * @param int $pricebook_id pricebook id.
162 * @param string $role user role.
163 */
164 private function addify_b2b( int $pricebook_id, string $role ): bool {
165 $price_book = $this->get_zoho_pricebook( $pricebook_id );
166 $zi_item_ids = $this->get_zoho_products();
167
168 if ( empty( $price_book ) ) {
169 return false;
170 }
171
172 $meta_collection = array();
173 if ( isset( $price_book['pricebook_type'] ) && $price_book['pricebook_type'] === 'fixed_percentage' ) {
174 $meta_collection['price'] = isset( $price_book['percentage'] ) ? $price_book['percentage'] : 0;
175 $meta_collection['ids'] = array_fill_keys( array_values( $zi_item_ids ), $meta_collection['price'] );
176 $meta_collection['orderby'] = $price_book['is_increase'] ? 'percentage_increase' : 'percentage_decrease';
177 } else {
178 $meta_collection['orderby'] = 'fixed_price';
179 foreach ( $price_book['pricebook_items'] as $itemlist ) {
180 if ( isset( $zi_item_ids[ $itemlist['item_id'] ] ) ) {
181 $meta_collection['ids'][ $zi_item_ids[ $itemlist['item_id'] ] ] = array();
182 if ( is_array( $itemlist['price_brackets'] ) && ! empty( $itemlist['price_brackets'] ) ) {
183 $price_bracket = $itemlist['price_brackets'][0];
184 $meta_collection['ids'][ $zi_item_ids[ $itemlist['item_id'] ] ] = array(
185 'start_quantity' => isset( $price_bracket['start_quantity'] ) ? $price_bracket['start_quantity'] : 0,
186 'end_quantity' => isset( $price_bracket['end_quantity'] ) ? $price_bracket['end_quantity'] : 0,
187 'pricebook_rate' => isset( $price_bracket['pricebook_rate'] ) ? $price_bracket['pricebook_rate'] : 0,
188 );
189 } else {
190 $meta_collection['ids'][ $zi_item_ids[ $itemlist['item_id'] ] ] = isset( $itemlist['pricebook_rate'] ) ? $itemlist['pricebook_rate'] : 0;
191 }
192 }
193 }
194 }
195
196 if ( empty( $meta_collection['ids'] ) ) {
197 return false;
198 }
199
200 foreach ( $meta_collection['ids'] as $product_id => $price ) {
201 $formatted_price = str_replace( '.', wc_get_price_decimal_separator(), $meta_collection['price'] ?? $price );
202 $metavalue = array(
203 'discount_type' => $meta_collection['orderby'],
204 'user_role' => $role,
205 'discount_value' => is_array( $formatted_price ) ? $formatted_price['pricebook_rate'] : $formatted_price,
206 'min_qty' => is_array( $formatted_price ) ? $formatted_price['start_quantity'] : '',
207 'max_qty' => is_array( $formatted_price ) ? $formatted_price['end_quantity'] : '',
208 );
209 $postmeta_array = get_post_meta( $product_id, '_role_base_price', true );
210 $updated = false;
211
212 if ( is_array( $postmeta_array ) && ! empty( $postmeta_array ) ) {
213 foreach ( $postmeta_array as &$postmeta ) {
214 if ( $postmeta['user_role'] === $role ) {
215 $postmeta = $metavalue;
216 $updated = true;
217 break;
218 }
219 }
220 if ( ! $updated ) {
221 $postmeta_array[] = $metavalue;
222 }
223 }
224
225 update_post_meta( $product_id, '_role_base_price', $postmeta_array );
226 }
227 return true;
228 }
229
230 /**
231 * Update price book for each group and its products.
232 *
233 * @param string $group_settings Group settings in JSON format.
234 *
235 * @return bool True if successful, false otherwise.
236 */
237 private function wc_b2b( $group_settings ): bool {
238 $group_settings = json_decode( $group_settings, true );
239 if ( empty( $group_settings ) ) {
240 return false;
241 }
242 foreach ( $group_settings as $group_setting ) {
243 $group_id = $group_setting['key'];
244 $pricebook_id = $group_setting['value'];
245 delete_transient( 'wcb2b_synced_groups' );
246 $price_book = $this->get_zoho_pricebook( $pricebook_id );
247 if ( empty( $price_book ) ) {
248 continue;
249 }
250 $zi_item_ids = $this->get_zoho_products();
251 switch ( $price_book['pricebook_type'] ) {
252 case 'fixed_percentage':
253 update_post_meta( $group_id, 'wcb2b_group_discount', $price_book['percentage'] );
254 update_post_meta( $group_id, 'pricebook_id', $pricebook_id );
255 update_post_meta( $group_id, 'pricebook_name', $price_book['name'] );
256 break;
257 case 'per_item':
258 foreach ( $price_book['pricebook_items'] as $pricebook_item ) {
259 if ( ! isset( $zi_item_ids[ $pricebook_item['item_id'] ] ) ) {
260 continue;
261 }
262 $product_id = $zi_item_ids[ $pricebook_item['item_id'] ];
263 $product_group_prices = array();
264 $product_group_min = array();
265 $product_group_max = array();
266 if ( is_array( $pricebook_item['price_brackets'] ) && count( $pricebook_item['price_brackets'] ) > 0 ) {
267 $price = $pricebook_item['price_brackets'][0]['pricebook_rate'];
268 $product_group_prices[ $group_id ]['regular_price'] = $price;
269 $product_group_min[ $group_id ] = $pricebook_item['price_brackets'][0]['start_quantity'];
270 $product_group_max[ $group_id ] = $pricebook_item['price_brackets'][0]['end_quantity'];
271 } else {
272 $product_group_prices[ $group_id ]['regular_price'] = $pricebook_item['pricebook_rate'];
273 }
274 update_post_meta( $group_id, 'pricebook_id', $pricebook_id );
275 update_post_meta( $group_id, 'pricebook_name', $price_book['name'] );
276 if ( ! empty( $product_group_prices ) ) {
277 update_post_meta( $product_id, 'wcb2b_product_group_prices', $product_group_prices );
278 }
279 if ( ! empty( $product_group_min ) ) {
280 update_post_meta( $product_id, 'wcb2b_product_group_min', $product_group_min );
281 }
282 if ( ! empty( $product_group_max ) ) {
283 update_post_meta( $product_id, 'wcb2b_product_group_max', $product_group_max );
284 }
285 }
286 break;
287 default:
288 break;
289 }
290 }
291
292 return true;
293 }
294
295 /**
296 * Retrieves and caches the WooCommerce B2B groups.
297 *
298 * @return array An associative array of group IDs as keys and their labels as values.
299 */
300 public function wc_b2b_groups() {
301 $in_cache = get_transient( 'wc_b2b_groups' );
302 if ( ! empty( $in_cache ) ) {
303 return $in_cache;
304 }
305 global $wpdb;
306
307 $results = $wpdb->get_results(
308 "SELECT ID AS id, post_title AS label
309 FROM {$wpdb->posts} p
310 WHERE p.post_type = 'wcb2b_group'
311 AND p.post_status = 'publish'",
312 ARRAY_A // Return results as an associative array.
313 );
314
315 if ( empty( $results ) ) {
316 return array();
317 }
318 $groups = wp_list_pluck( $results, 'label', 'id' );
319 set_transient( 'wc_b2b_groups', $groups, DAY_IN_SECONDS );
320
321 return $groups;
322 }
323
324 /**
325 * Retrieves and caches the B2B groups from the database.
326 *
327 * @return array The B2B groups data.
328 */
329 private function wc_b2b_groups_by_rule() {
330 $in_cache = get_transient( 'wc_b2b_groups' );
331 if ( ! empty( $in_cache ) ) {
332 return $in_cache;
333 }
334 global $wpdb;
335
336 $results = $wpdb->get_results(
337 "SELECT p . ID as id, pm . meta_value as rule
338 FROM {$wpdb->posts} p
339 INNER JOIN {$wpdb->postmeta} pm ON p . ID = pm . post_id
340 WHERE p . post_type = 'wcb2b_group'
341 and pm . meta_key = 'wcb2b_group_price_rule'",
342 ARRAY_A // Return results as an associative array.
343 );
344
345 if ( empty( $results ) ) {
346 return array();
347 }
348 $grouped_data = array_reduce(
349 $results,
350 function ( $result, $item ) {
351 $result[ $item['rule'] ][] = $item['id'];
352
353 return $result;
354 },
355 array()
356 );
357
358 set_transient( 'wc_b2b_groups', $grouped_data, DAY_IN_SECONDS );
359
360 return $grouped_data;
361 }
362 }
363