(in-package :cl-user) (defpackage chatikbot.plugins.zsd (:use :cl :chatikbot.common)) (in-package :chatikbot.plugins.zsd) (defparameter +zsd-api-url+ "https://mcabinet.nch-spb.com/onyma/system/api/json") (defparameter +zsd-auth-url+ "https://mcabinet.nch-spb.com/onyma/system/api/jsonex?function=open_session") (defun %zsd/api (token method &optional args) (let* ((f (concatenate 'string "onm_api_toll_api_" method)) (params (loop for (k . v) in args when v collect (cons (princ-to-string k) (princ-to-string v)))) (response (json-request +zsd-api-url+ :parameters (append params `(("function" . ,f) ("auth_token" . ,token)))))) (values (aget "return" response) (aget "more_rows" response)))) (defun zsd/auth (login password) (aget "return" (json-request +zsd-auth-url+ :method :post :content (plist-json (list :realm "WHSD" :user login :pass password))))) (defun zsd/pan (token) (%zsd/api token "mobile_pan")) (defun zsd/contract (token) (%zsd/api token "contract_info")) (defun zsd/wall (token &optional (offset 0) (limit 5)) (%zsd/api token "mobile_wall" `(("rows_skip" . ,offset) ("rows_limit" . ,limit)))) (defun zsd/load-data (token &optional (limit 5)) `(("contract" . ,(zsd/contract token)) ("pan" . ,(zsd/pan token)) ("wall" . ,(zsd/wall token 0 limit)))) (defun %zsd/format-wall (item pans) (let* ((pan (aget "pan" item)) (alias (aget "alias" (find pan pans :test #'equal :key (lambda (el) (aget "pan" el))))) (event (parse-integer (aget "event_type" item))) (amount (aget "amount" item)) (entry (aget "entry_place" item)) (place (aget "place" item)) (cdt (aget "cdt" item))) (case event (1 (format nil "~A *~aр.*: 🚗 ~a, _~a → ~a_" cdt amount (or alias pan) entry place)) (101 (format nil "~A *~aр.*: 💶 _~a_" cdt amount place))))) (defun zsd/format-changes (old new) (let ((wall-diff (set-difference (aget "wall" new) (aget "wall" old) :test #'equal))) (when wall-diff (format nil "ЗСД остаток: *~$р.*~%~%~{~A~^~%~}" (parse-float (aget "remainder" (car (aget "contract" new)))) (loop for item in wall-diff collect (%zsd/format-wall item (aget "pan" new))))))) (defun zsd/handle-set-cron (enable) (lists-set-entry :zsd *chat-id* enable) (bot-send-message (if enable "Включил рассылку. '/zsd off' чтобы выключить, /zsd - показать последние." "Без рассылки. '/zsd on' - включить, /zsd - последние."))) (defun zsd/handle-auth (login pass) (let ((token (zsd/auth login pass))) (if token (progn (secret-set `(:zsd ,*chat-id*) token) (zsd/handle-set-cron t)) (bot-send-message "Чот не смог, пропробуй другие.")))) (defun zsd/handle-recent () (with-secret (token (list :zsd *chat-id*)) (bot-send-message (if token (let ((data (zsd/load-data token))) (if data (zsd/format-changes nil data) "Не смог получить данные. Попробуй перелогинься. /zsd ")) "Нужен логин-пароль. /zsd ") :parse-mode "markdown"))) (def-message-cmd-handler handle-cmd-zsd (:zsd) (cond ((= 1 (length *args*)) (zsd/handle-set-cron (equal "on" (car *args*)))) ((= 2 (length *args*)) (apply 'zsd/handle-auth *args*)) (:otherwise (zsd/handle-recent)))) (defvar *zsd/last-results* (make-hash-table) "Last check results") (defcron process-zsd (:minute '(member 0 10 20 30 40 50)) (dolist (*chat-id* (lists-get :zsd)) (with-secret (token (list :zsd *chat-id*)) (if token (let ((old (gethash *chat-id* *zsd/last-results*)) (new (zsd/load-data token))) (when new (when old (alexandria:when-let ((changes (zsd/format-changes old new))) (bot-send-message changes :parse-mode "markdown"))) (setf (gethash *chat-id* *zsd/last-results*) new))) (progn (log:warn "zsd no token for" *chat-id*))))))