#|

src/models/crystal-commerce.lisp

Crystal Commerce-style Inventory Management Backend

TODO All of the old style database accessores (*-BY-ID, etc) need to go.

DONE It looks like the CSV listing is totally outdated after all:

CL-DECK-BUILDER2> (count-dao 'cc-item)
48883 (16 bits, #xBEF3)
CL-DECK-BUILDER2> (count-dao 'cl-deck-builder2.models.ygoprodeck.classes::ygo-set)
49240 (16 bits, #xC058)

That's awfully close enough for me, taking into account the art cards,
the duelist name tag, and prize cards! I wonder if there'd be a way to
see the diff. Some cards are name "Dark Magician A" which is
unfortunate!

TODO Because of the previous item being DONE, this code is now
outdated and stale, and probably safe to delete, unless we intend on
doing more with Crystal Commerce in the future.

|#

(in-package #:cl-user)

(defpackage #:cl-deck-builder2.models.crystal-commerce
  (:use #:cl
        #:cl-deck-builder2.db
        #:cl-deck-builder2.models.generics
        #:cl-deck-builder2.toolkit.money
        #:cl-deck-builder2.models.registered-table
        #:cl-deck-builder2.models.ygoprodeck)
  (:import-from #:cl-deck-builder2.models.ygoprodeck.fields
                #:variant-condition)
  (:export
   :cc-item
   :ygo-cc-item

   :name-of
   :cc-category-of
   :cc-wishlists-of
   :cc-buy-price-of
   :cc-sell-price-of
   :cc-url-of
   :cc-barcode-of
   :cc-manufacturer-sku-of
   :cc-asin-of
   :cc-msrp-of
   :cc-brand-of
   :cc-weight-of
   :cc-description-of
   :cc-qty-of
   :cc-max-qty-of
   :cc-total-qty-of
   :cc-domestic-only-of
   :cc-tax-exempt-of
   :cc-name-of
   :cc-code-of
   :cc-rarity-of
   :cc-edition-of
   :cc-passcode-of

   :cc-table-ensure-exists
   :cc-table-drop
   :cc-table-delete
   :cc-table-select
   :cc-table-select-count
   :cc-table-zero

   :cc-select-by-id
   :cc-select-by-passcode

   :cc-delete-by-id

   :cc-create

   :cc-variant-of))

(in-package #:cl-deck-builder2.models.crystal-commerce)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cards v2
;;
(defclass cc-item ()
  ((name :accessor name-of
         :col-type :text)
   (category :accessor cc-category-of
             :col-type :text)
   (total-qty :accessor cc-total-qty-of
              :col-type :integer
              :initform 0)
   (wishlists :accessor cc-wishlists-of
              :col-type :integer
              :initform 0)
   (;; 10 cent buy price
    buy-price :accessor cc-buy-price-of
              :col-type :integer
              :initform 0.10
              :inflate #'currency-inflate
              :deflate #'currency-deflate)
   (;; 50 cent sell price
    sell-price :accessor cc-sell-price-of
               :col-type :integer
               :initform 0.50
               :inflate #'currency-inflate
               :deflate #'currency-deflate)
   (url :accessor cc-url-of
        :col-type (or :text :null))
   (barcode :accessor cc-barcode-of
            :col-type (or :text :null))
   (manufacturer-sku :accessor cc-manufacturer-sku-of
                     :col-type (or :text :null))
   ;; Some cards don't have an ASIN: Prize Cards, for example.
   ;;
   ;; ASIN is a built in LISP function so this seems to be causing
   ;; issues with Djula.  I renamed it to AMAZON-ASIN.
   (amazon-asin :accessor cc-asin-of
                :col-type (or :text :null))
   (msrp :accessor cc-msrp-of
         :col-type (or :integer :null)
         :inflate #'currency-inflate
         :deflate #'currency-deflate)
   (brand :accessor cc-brand-of
          :col-type (or :text :null))
   ;; Weight in pounds, lb, lbs.. silly
   (weight :accessor cc-weight-of
           :col-type :text
           :initform "0.0625")
   (description :accessor cc-description-of
                :col-type (or :text :null))
   (max-qty :accessor cc-max-qty-of
            :col-type (or :integer :null))
   (domestic-only :accessor cc-domestic-only-of
                  :col-type :integer
                  :initform 0)
   (tax-exempt :accessor cc-tax-exempt-of
               :col-type :integer
               :initform 0))
  (:metaclass registered-table-class)
  (:documentation "The base data from CrystalCommerce. This is what's available in a CSV export.

These fields can be updated from CC CSV Export Search feature.
  
The product descriptors. Contains information about the actual content
of the card. None of this is available via CC CSV Export Feature. This
information has to be updated aftewards. The Mass Updater may have
some hints as to how this works.

Other stuff that doesn't appear in any export or search feature, but on YGOProDeck, which we will probably take info from."))

;; Allow bogus keys so we can just apply #'make-instance 'cc-item _parsed in web view
; (defmethod initialize-instance :after ((cc-item cc-item) &key &allow-other-keys))

(defclass ygo-cc-item ()
  ((item :accessor cc-item-of
         :col-type cc-item)
   (variant :accessor cc-variant-of
            :col-type variant-condition)
   (qty :accessor cc-qty-of
        :col-type :integer
        :initform 0)
   (opt-qty :accessor cc-opt-qty-of
            :col-type :integer
            :initform 0)
   (;; 10 cent buy price
    buy-price :accessor cc-buy-price-of
              :col-type :integer
              :initform 0.10
              :inflate #'currency-inflate
              :deflate #'currency-deflate)
   (;; 50 cent sell price
    sell-price :accessor cc-sell-price-of
               :col-type :integer
               :initform 0.50
               :inflate #'currency-inflate
               :deflate #'currency-deflate))
  (:metaclass registered-table-class)
  (:documentation "CC-ITEM + VARIANT relationship table."))


(defmacro cc-table-delete (&body clauses)
  `(delete-from 'cc-item ,@clauses))

(defmacro cc-table-select (&body body)
  `(select-dao 'cc-item ,@body))

(defun cc-table-select-count (&optional fields-and-values)
  (count-dao 'cc-item fields-and-values))


;; TODO toolkit/db.lisp maybe?
(defun zero-field (class field &optional clauses)
  "Set the specified FIELD of CLASS zero. You may additionally specify CLAUSES."
  (with-connection (db)
    (with-transaction
      (mito:execute-sql
       (sxql:update (sxql:make-sql-symbol
                     (mito.dao::table-name (find-class class)))
         (sxql:set= (sxql:make-sql-symbol field) 0)
         clauses)))))

(defun set-buy-sell-price (&optional (buy-price 10) (sell-price 50))
  "This bypasses MITO:DEFLATE (the argument is in CENTS)."
  (with-connection (db)
    (with-transaction
      (mito:execute-sql
       (sxql:update :cc_item
         (sxql:set= (sxql:make-sql-symbol "buy_price") buy-price
                    (sxql:make-sql-symbol "sell_price") sell-price))
       (sxql:update :ygo_cc_item
         (sxql:set= (sxql:make-sql-symbol "buy_price") buy-price
                    (sxql:make-sql-symbol "sell_price") sell-price))))))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cc-select-by-id (id &rest args)
  (apply #'find-dao 'cc-item :id id args))

(defun cc-select-by-passcode (passcode &rest args)
  (apply #'find-dao 'cc-item :passcode passcode args))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INSERT

(defun cc-create (&rest args)
  (apply #'create-dao 'cc-item args))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DELETE
(defun cc-delete-by-id (id &rest args)
  (apply #'delete-by-values 'cc-item :id id args))
