Plugin Directory

source: erp/trunk/modules/accounting/includes/functions/products.php

Last change on this file was 3168426, checked in by wedevs, 6 months ago

Update codebase of 1.13.3

File size: 20.3 KB
Line 
1<?php
2
3if ( ! defined( 'ABSPATH' ) ) {
4    exit; // Exit if accessed directly
5}
6
7
8/**
9 * Get all products
10 *
11 * @return mixed
12 */
13
14function erp_acct_get_all_products( $args = [] ) {
15    global $wpdb;
16
17    $defaults = [
18        'number'  => 20,
19        'offset'  => 0,
20        'orderby' => 'id',
21        'order'   => 'DESC',
22        'count'   => false,
23        's'       => '',
24    ];
25
26    $args = wp_parse_args( $args, $defaults );
27
28    $last_changed = erp_cache_get_last_changed( 'accounting', 'products', 'erp-accounting' );
29    $cache_key    = 'erp-get-products-' . md5( serialize( $args ) ) . ": $last_changed";
30    $products     = wp_cache_get( $cache_key, 'erp-accounting' );
31
32    $cache_key_count = 'erp-get-products-count-' . md5( serialize( $args ) ) . ": $last_changed";
33    $products_count  = wp_cache_get( $cache_key_count, 'erp-accounting' );
34
35    if ( false === $products ) {
36        $limit = '';
37
38        if ( -1 !== $args['number'] ) {
39            $limit = $wpdb->prepare( "LIMIT %d OFFSET %d", $args['number'], $args['offset'] );
40        }
41
42        $sql = 'SELECT';
43
44        if ( $args['count'] ) {
45            $sql .= ' COUNT( product.id ) as total_number';
46        } else {
47            $sql .= " product.id,
48                    product.name,
49                    product.product_type_id,
50                    product.cost_price,
51                    product.sale_price,
52                    product.tax_cat_id,
53                    people.id AS vendor,
54                    CONCAT(people.first_name, ' ',  people.last_name) AS vendor_name,
55                    cat.id AS category_id,
56                    cat.name AS cat_name,
57                    product_type.name AS product_type_name";
58        }
59
60        $sql .= " FROM {$wpdb->prefix}erp_acct_products AS product
61            LEFT JOIN {$wpdb->prefix}erp_peoples AS people ON product.vendor = people.id
62            LEFT JOIN {$wpdb->prefix}erp_acct_product_categories AS cat ON product.category_id = cat.id
63            LEFT JOIN {$wpdb->prefix}erp_acct_product_types AS product_type ON product.product_type_id = product_type.id
64            WHERE product.product_type_id<>3";
65
66        if ( ! empty( $args['s'] ) ) {
67            $sql .= ' AND product.name LIKE %s';
68            $search_str = '%' . $wpdb->esc_like( $args['s'] ) . '%';
69            $sql = $wpdb->prepare( $sql, $search_str ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
70        }
71
72        // To use wpdb prepare, we need to add and %d=%d to achieve where 1=1
73        $sql .= " ORDER BY product.{$args['orderby']} {$args['order']} {$limit}";
74
75        erp_disable_mysql_strict_mode();
76
77        if ( $args['count'] ) {
78            $products_count = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
79
80            wp_cache_set( $cache_key_count, $products_count, 'erp-accounting' );
81        } else {
82            $products = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
83
84            wp_cache_set( $cache_key, $products, 'erp-accounting' );
85        }
86    }
87
88    if ( $args['count'] ) {
89        return $products_count;
90    }
91
92    return $products;
93}
94
95/**
96 * Get an single product
97 *
98 * @param $product_no
99 *
100 * @return mixed
101 */
102function erp_acct_get_product( $product_id ) {
103    global $wpdb;
104
105    erp_disable_mysql_strict_mode();
106
107    $row = $wpdb->get_row(
108        $wpdb->prepare(
109            "SELECT
110            product.id,
111            product.name,
112            product.product_type_id,
113            product.cost_price,
114            product.sale_price,
115            product.tax_cat_id,
116            people.id AS vendor,
117            CONCAT(people.first_name, ' ',  people.last_name) AS vendor_name,
118            cat.id AS category_id,
119            cat.name AS cat_name,
120            product_type.name AS product_type_name
121
122                FROM {$wpdb->prefix}erp_acct_products AS product
123                LEFT JOIN {$wpdb->prefix}erp_peoples AS people ON product.vendor = people.id
124                LEFT JOIN {$wpdb->prefix}erp_acct_product_categories AS cat ON product.category_id = cat.id
125        LEFT JOIN {$wpdb->prefix}erp_acct_product_types AS product_type ON product.product_type_id = product_type.id WHERE product.id = %d LIMIT %d",
126            $product_id, 1
127        ),
128        ARRAY_A
129    );
130
131    return $row;
132}
133
134/**
135 * Insert product data
136 *
137 * @param $data
138 * @return WP_Error | integer
139 */
140function erp_acct_insert_product( $data ) {
141    global $wpdb;
142
143    $created_by         = get_current_user_id();
144    $data['created_at'] = gmdate( 'Y-m-d H:i:s' );
145    $data['created_by'] = $created_by;
146    $product_id         = null;
147
148    try {
149        $wpdb->query( 'START TRANSACTION' );
150        $product_data = erp_acct_get_formatted_product_data( $data );
151
152        $product_check =  $wpdb->get_row(
153            $wpdb->prepare(
154                "SELECT * FROM {$wpdb->prefix}erp_acct_products where name = %s",
155                $product_data['name']
156            ),
157            OBJECT
158        );
159
160        if ( $product_check ) {
161           throw new \Exception( $product_data['name'] . ' ' . __( 'product already exists!', 'erp' ) ) ;
162        }
163
164        $wpdb->insert(
165            $wpdb->prefix . 'erp_acct_products',
166            [
167                'name'            => $product_data['name'],
168                'product_type_id' => $product_data['product_type_id'],
169                'category_id'     => $product_data['category_id'],
170                'tax_cat_id'      => $product_data['tax_cat_id'],
171                'vendor'          => $product_data['vendor'],
172                'cost_price'      => $product_data['cost_price'],
173                'sale_price'      => $product_data['sale_price'],
174                'created_at'      => $product_data['created_at'],
175                'created_by'      => $product_data['created_by'],
176                'updated_at'      => $product_data['updated_at'],
177                'updated_by'      => $product_data['updated_by'],
178            ]
179        );
180
181        $product_id = $wpdb->insert_id;
182
183        $wpdb->query( 'COMMIT' );
184    } catch ( Exception $e ) {
185        $wpdb->query( 'ROLLBACK' );
186        return new WP_Error( 'duplicate-product', $e->getMessage(), array( 'status' => 400 ) );
187    }
188
189    erp_acct_purge_cache( ['list' => 'products,products_vendor'] );
190
191    do_action( 'erp_acct_after_change_product_list' );
192
193    return erp_acct_get_product( $product_id );
194}
195
196/**
197 * Update product data
198 *
199 * @param $data
200 *
201 * @return WP_Error | Object
202 */
203function erp_acct_update_product( $data, $id ) {
204    global $wpdb;
205
206    $updated_by         = get_current_user_id();
207    $data['updated_at'] = gmdate( 'Y-m-d H:i:s' );
208    $data['updated_by'] = $updated_by;
209
210    try {
211        $wpdb->query( 'START TRANSACTION' );
212        $product_data = erp_acct_get_formatted_product_data( $data );
213
214        $product_name_check =  $wpdb->get_row(
215            $wpdb->prepare(
216                "SELECT * FROM {$wpdb->prefix}erp_acct_products where name = %s AND id NOT IN(%d)",
217                $product_data['name'],
218                $id
219            ),
220            OBJECT
221        );
222
223        if ( $product_name_check ) {
224            throw new \Exception( $product_data['name'] . ' ' . __( "Product name already exists!" , "erp") ) ;
225        }
226
227        $wpdb->update(
228            $wpdb->prefix . 'erp_acct_products',
229            [
230                'name'            => $product_data['name'],
231                'product_type_id' => $product_data['product_type_id'],
232                'category_id'     => $product_data['category_id'],
233                'tax_cat_id'      => $product_data['tax_cat_id'],
234                'vendor'          => $product_data['vendor'],
235                'cost_price'      => $product_data['cost_price'],
236                'sale_price'      => $product_data['sale_price'],
237                'created_at'      => $product_data['updated_at'],
238                'created_by'      => $product_data['updated_by'],
239                'updated_at'      => $product_data['updated_at'],
240                'updated_by'      => $product_data['updated_by'],
241            ],
242            [
243                'id' => $id,
244            ]
245        );
246
247        $wpdb->query( 'COMMIT' );
248    } catch ( Exception $e ) {
249        $wpdb->query( 'ROLLBACK' );
250
251        return new WP_Error( 'duplicate-product', $e->getMessage(), array( 'status' => 400 ) );
252    }
253
254    erp_acct_purge_cache( ['list' => 'products,products_vendor'] );
255
256    do_action( 'erp_acct_after_change_product_list' );
257
258    return erp_acct_get_product( $id );
259}
260
261/**
262 * Get formatted product data
263 *
264 * @param $data
265 * @param $voucher_no
266 *
267 * @return mixed
268 */
269function erp_acct_get_formatted_product_data( $data ) {
270    $product_data['name']            = ! empty( $data['name'] ) ? $data['name'] : 1;
271    $product_data['product_type_id'] = ! empty( $data['product_type_id'] ) ? $data['product_type_id'] : 1;
272    $product_data['category_id']     = ! empty( $data['category_id'] ) ? $data['category_id'] : 0;
273    $product_data['tax_cat_id']      = ! empty( $data['tax_cat_id'] ) ? $data['tax_cat_id'] : 0;
274    $product_data['vendor']          = ! empty( $data['vendor'] ) ? $data['vendor'] : '';
275    $product_data['cost_price']      = ! empty( $data['cost_price'] ) ? $data['cost_price'] : '';
276    $product_data['sale_price']      = ! empty( $data['sale_price'] ) ? $data['sale_price'] : '';
277    $product_data['created_at']      = ! empty( $data['created_at'] ) ? $data['created_at'] : '';
278    $product_data['created_by']      = ! empty( $data['created_by'] ) ? $data['created_by'] : '';
279    $product_data['updated_at']      = ! empty( $data['updated_at'] ) ? $data['updated_at'] : '';
280    $product_data['updated_by']      = ! empty( $data['updated_by'] ) ? $data['updated_by'] : '';
281
282    return $product_data;
283}
284
285/**
286 * Delete an product
287 *
288 * @param $product_no
289 *
290 * @return int
291 */
292function erp_acct_delete_product( $product_id ) {
293    global $wpdb;
294
295    $wpdb->delete( $wpdb->prefix . 'erp_acct_products', [ 'id' => $product_id ] );
296    $wpdb->delete( $wpdb->prefix . 'erp_acct_product_details', [ 'product_id' => $product_id ] );
297
298    erp_acct_purge_cache( ['list' => 'products,products_vendor'] );
299
300    do_action( 'erp_acct_after_change_product_list' );
301
302    return $product_id;
303}
304
305/**
306 * Get product types
307 *
308 * @param $product_id
309 *
310 * @return int
311 */
312function erp_acct_get_product_types() {
313    global $wpdb;
314
315    $types = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}erp_acct_product_types" );
316
317    return apply_filters( 'erp_acct_product_types', $types );
318}
319
320/**
321 * Get product type id by product id
322 *
323 * @param $product_id
324 *
325 * @return int
326 */
327function erp_acct_get_product_type_id_by_product_id( $product_id ) {
328    global $wpdb;
329
330    $type_id = $wpdb->get_var( $wpdb->prepare( "SELECT product_type_id FROM {$wpdb->prefix}erp_acct_products WHERE id = %d", $product_id ) );
331
332    return $type_id;
333}
334
335/**
336 * Get all products of a vendor
337 *
338 * @return mixed
339 */
340function erp_acct_get_vendor_products( $args = [] ) {
341    global $wpdb;
342
343    $defaults = [
344        'number'  => 20,
345        'offset'  => 0,
346        'orderby' => 'id',
347        'order'   => 'DESC',
348        'count'   => false,
349        's'       => '',
350        'vendor'  => 0,
351    ];
352
353    $args = wp_parse_args( $args, $defaults );
354
355    $last_changed    = erp_cache_get_last_changed( 'accounting', 'products_vendor', 'erp-accounting' );
356    $cache_key       = 'erp-get-products_vendor-' . md5( serialize( $args ) ) . ": $last_changed";
357    $products_vendor = wp_cache_get( $cache_key, 'erp-accounting' );
358
359    $cache_key_count       = 'erp-get-products_vendor-count-' . md5( serialize( $args ) ) . ": $last_changed";
360    $products_vendor_count = wp_cache_get( $cache_key_count, 'erp-accounting' );
361
362    if ( false === $products_vendor ) {
363        $limit = '';
364
365        if ( -1 !== $args['number'] ) {
366            $limit = $wpdb->prepare( "LIMIT %d OFFSET %d", $args['number'], $args['offset'] );
367        }
368
369        $sql = 'SELECT';
370
371        if ( $args['count'] ) {
372            $sql .= ' COUNT( product.id ) as total_number';
373        } else {
374            $sql .= " product.id,
375                product.name,
376                product.product_type_id,
377                product.cost_price,
378                product.sale_price,
379                product.tax_cat_id,
380                product.vendor,
381                CONCAT(people.first_name, ' ',  people.last_name) AS vendor_name,
382                cat.id AS category_id,
383                cat.name AS cat_name,
384                product_type.name AS product_type_name";
385        }
386
387        // Build the FROM and JOIN parts of the query separately
388        $sql .= $wpdb->prepare( " FROM {$wpdb->prefix}erp_acct_products AS product
389            LEFT JOIN {$wpdb->prefix}erp_peoples AS people ON product.vendor = people.id
390            LEFT JOIN {$wpdb->prefix}erp_acct_product_categories AS cat ON product.category_id = cat.id
391            LEFT JOIN {$wpdb->prefix}erp_acct_product_types AS product_type ON product.product_type_id = product_type.id
392            WHERE people.id = %d AND product.product_type_id <> %d", $args['vendor'], 3 );
393
394        // Append the ORDER BY clause
395        $sql .= " ORDER BY product.{$args['orderby']} {$args['order']}";
396
397        // Append the LIMIT clause if needed
398        if ( ! empty( $limit ) ) {
399            $sql .= " $limit";
400        }
401
402        if ( $args['count'] ) {
403            $products_vendor_count = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
404
405            wp_cache_set( $cache_key_count, $products_vendor_count, 'erp-accounting' );
406        } else {
407            $products_vendor = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
408
409            wp_cache_set( $cache_key, $products_vendor, 'erp-accounting' );
410        }
411    }
412
413    if ( $args['count'] ) {
414        return $products_vendor_count;
415    }
416
417    return $products_vendor;
418}
419
420/**
421 * Validates csv data for importing
422 *
423 * @since 1.9.0
424 *
425 * @param array $data
426 *
427 * @return array|WP_Error
428 */
429function erp_acct_validate_csv_data( $data ) {
430    $files = wp_check_filetype_and_ext( $data['csv_file']['tmp_name'], $data['csv_file']['name'] );
431
432    if ( 'csv' !== $files['ext'] && 'text/csv' !== $files['type'] ) {
433        return new WP_Error( 'invalid-file-type', __( 'The file is not a valid CSV file! Please provide a valid one.', 'erp' ) );
434    }
435
436    $csv = new \ParseCsv\Csv();
437    $csv->encoding( null, 'UTF-8' );
438    $csv->parse( $data['csv_file']['tmp_name'] );
439
440    if ( empty( $csv->data ) ) {
441        return new WP_Error( 'no-data', __( 'No data found to import!', 'erp' ) );
442    }
443
444    $csv_data   = [];
445    $csv_data[] = array_keys( $csv->data[0] );
446
447    foreach ( $csv->data as $data_item ) {
448        $csv_data[] = array_values( $data_item );
449    }
450
451    if ( empty( $csv_data ) ) {
452        return new WP_Error( 'no-data', __( 'No data found to import!', 'erp' ), [ 'status' => 400 ] );
453    }
454
455    $count           = 0;
456    $errors          = [];
457    $product_data    = [];
458    $to_be_updated   = [];
459    $processed_data  = '';
460    $temp_type       = $data['type'];
461    $update_existing = (int) $data['update_existing'] ? true : false;
462    $curr_date       = erp_current_datetime()->format( 'Y-m-d' );
463    $user            = get_current_user_id();
464
465    if ( $update_existing ) {
466        $temp_type = 'product_non_unique';
467    }
468
469    $errors = apply_filters( 'erp_validate_csv_data', $csv_data, $data['fields'], $temp_type );
470
471    if ( ! empty( $errors ) ) {
472        return new WP_Error( 'import-error', $errors );
473    }
474
475    unset( $csv_data[0] );
476
477    foreach ( $csv_data as $index => $line ) {
478        if ( empty( $line ) ) {
479            continue;
480        }
481
482        if ( is_array( $data['fields'] ) && ! empty( $data['fields'] ) ) {
483            $product_data[ $index ] = '';
484            $product_exists_id      = '';
485            $product_checked        = false;
486
487            global $wpdb;
488
489            foreach ( $data['fields'] as $key => $value ) {
490
491                switch ( $key ) {
492
493                    case 'category_id':
494
495                        if ( ! empty( $line[ $value ] ) ) {
496                            $valid_value = $wpdb->get_var(
497                                "SELECT id
498                                FROM {$wpdb->prefix}erp_acct_product_categories
499                                WHERE id = {$line[ $value ]}"
500                            );
501                        }
502
503                        break;
504
505                    case 'product_type_id':
506
507                        if ( ! empty( $line[ $value ] ) ) {
508                            $valid_value = $wpdb->get_var(
509                                "SELECT id
510                                FROM {$wpdb->prefix}erp_acct_product_types
511                                WHERE id = {$line[ $value ]}"
512                            );
513                        }
514
515                        break;
516
517                    case 'tax_cat_id':
518
519                        if ( ! empty( $line[ $value ] ) ) {
520                            $valid_value = $wpdb->get_var(
521                                "SELECT id
522                                FROM {$wpdb->prefix}erp_acct_tax_categories
523                                WHERE id = {$line[ $value ]}"
524                            );
525                        }
526
527                        break;
528
529                    case 'vendor':
530
531                        if ( ! empty( $line[ $value ] ) ) {
532                            $valid_value = $wpdb->get_var(
533                                "SELECT people.id
534                                FROM {$wpdb->prefix}erp_peoples AS people
535                                LEFT JOIN {$wpdb->prefix}erp_people_type_relations AS rel
536                                ON people.id = rel.people_id
537                                WHERE people.id = {$line[ $value ]}
538                                AND rel.people_types_id = 4"
539                            );
540                        }
541
542                        break;
543
544                    default:
545                        $valid_value = true;
546                }
547
548                $value = ! empty( $line[ $value ] ) &&
549                         ! empty( $valid_value )
550                         ? $line[ $value ]
551                         : (
552                            ! empty( $data[ $key ] )
553                            ? $data[ $key ]
554                            : ''
555                         );
556
557                if ( $update_existing && ! $product_checked && 'name' === $key ) {
558                    $product_exists_id =  $wpdb->get_var(
559                        $wpdb->prepare(
560                            "SELECT id FROM {$wpdb->prefix}erp_acct_products where name = %s",
561                            $value
562                        )
563                    );
564
565                    $product_checked = true;
566                }
567
568                if ( empty( $product_exists_id ) ) {
569                    $product_data[ $index ] .= "'{$value}',";
570                } else {
571                    $to_be_updated[ $product_exists_id ][ $key ] = $value;
572                }
573            }
574
575            if ( empty( $product_exists_id ) ) {
576                $product_data[ $index ] .= "'{$user}','{$curr_date}'";
577            } else {
578                unset( $product_data[ $index ] );
579            }
580
581            ++ $count;
582        }
583    }
584
585    if ( ! empty( $product_data ) ) {
586        $processed_data = '(' . implode( '),(', $product_data ) . ')';
587    }
588
589    return [
590        'data'   => $processed_data,
591        'update' => $to_be_updated,
592        'total'  => $count
593    ];
594}
595
596/**
597 * Imports products from csv
598 *
599 * @since 1.9.0
600 *
601 * @param array $data
602 *
603 * @return int|WP_Error
604 */
605function erp_acct_import_products( $data ) {
606    global $wpdb;
607
608    if ( ! empty( $data['items'] ) ) {
609        $inserted = $wpdb->query(
610            $wpdb->prepare(
611                "INSERT INTO {$wpdb->prefix}erp_acct_products
612                 (name, product_type_id, category_id, cost_price, sale_price, vendor, tax_cat_id, created_by, created_at)
613                VALUES %s",
614                $data['items']
615            )
616        );
617
618        if ( is_wp_error( $inserted ) ) {
619            return new WP_Error( 'import-db-error', __( 'Something went wrong', 'erp' ) );
620        }
621    }
622
623    if ( ! empty( $data['update'] ) ) {
624        $curr_date = erp_current_datetime()->format( 'Y-m-d' );
625        $user      = get_current_user_id();
626
627        foreach ( $data['update'] as $id => $field_data ) {
628            $field_data['updated_at'] = $curr_date;
629            $field_data['updated_by'] = $user;
630
631            $wpdb->update( "{$wpdb->prefix}erp_acct_products", $field_data, [ 'id' => $id ] );
632        }
633    }
634
635    if ( 0 >= (int) $data['total'] ) {
636        return new WP_Error( 'import-error', __( 'No data imported', 'erp' ) );
637    }
638
639    return $data['total'];
640}
Note: See TracBrowser for help on using the repository browser.