
誰ããèªåã®ããžãã¹ãéå§ããããšã決ããä»®æ³ãã¹ãã£ã³ã°ãæäŸãããã©ã³ãã£ã€ãºã®ããã«è±ãã³ãŒããŒã®è²©å£²ã®ããã®ãªã³ã©ã€ã³ãµãŒãã¹ãéå§ãããå Žåãä»äºãæŽçããããã®å€ãã®æ¢è£œã®ããŒã«ããããŸãã äžæ¹ãåçŽã«ããžãã¹ãéå§ããå Žåã¯ããã®åéã®å€æ°ã®ç«¶åä»ç€Ÿã«åããå¿ èŠããããŸãã ãçãå°œããã®å¯èœæ§ãé«ãŸããŸãã
競äºã®å°ãªãéçºãäžååãªå°åã«è¡ããšãã¿ã¹ã¯ãèªååããããã®æ¢è£œã®ããŒã«ããªãå ŽåããããŸãã ã¯ããæåã¯ãã¹ãŠãæåã§è¡ãããšãã§ããŸããã顧客ã®æ°ãå¢ãããšãããã»ã¹ã®æé©åã«ã€ããŠçå£ã«èããå¿ èŠããããŸãã
èªååããŒã«ãéçºãããšããCOREmanagerãã¬ãŒã ã¯ãŒã¯ãåºç€ãã¹ã±ã«ãã³ã補åãšããŠäœ¿çšã§ããŸãã ããã«ãããã³ãŒãã£ã³ã°ã«è²»ããæéãççž®ãããããŸããŸãªããã°ã©ãã³ã°èšèªã䜿çšããŠããŸããŸãªæ©èœãå®è£ ã§ããŸãã
ã«ããã®äž-ISPlicenseã«ããå€éšå§èšæè¡ãµããŒãã·ã¹ãã ã®éçºã®è©³çŽ°ã
ISPlicenseã¯ã競äºã®æ¿ããããžãã¹åéã§é©æ°çãªãµãŒãã¹ãæäŸããäŒç€Ÿã®ä»£è¡šçãªäŸã§ãã 圌ãã¯ãã¹ãã£ã³ã°ã»ã¯ã¿ãŒãéžæããåžå Žã«åå ¥ããæ¢åããã³æ°èŠãã¬ãŒã€ãŒã«ãµãŒãã¹ãæäŸããããžãã¹ã¢ãã«ãæ§ç¯ããŸããã ISPsystemãœãããŠã§ã¢è£œåã®ã©ã€ã»ã³ã¹ãå販ããããšããå§ããåœç€Ÿã®äž»èŠããŒãããŒã®1ã€ã«ãªããŸããã ãã°ããããŠãå瀟ã®ãµãŒãã¹ããã±ãŒãžã¯ã ã¢ãŠããœãŒã·ã³ã°ãã¯ãã«ã«ãµããŒãã®æäŸã«ãã£ãŠè£å®ãããŸããã ãªãœãŒã¹ã®äžè¶³ãã»ãšãã©ã®ã¯ã©ã€ã¢ã³ãããã®å°ççãªé éæ§ãããã³ãã®ä»ã®çç±ã«ãããå€ãã®ãã¹ãã£ã³ã°äºæ¥è ã¯ãµãŒãããŒãã£çµç¹ã«æè¡ãµããŒããæäŸããããšãçå£ã«èããŸããã
ISPlicenseã¯ã2ã€ã®æ¹æ³ã§ã¢ãŠããœãŒã·ã³ã°ãã¯ãã«ã«ãµããŒããæäŸããŸãã
- ãšã³ããŠãŒã¶ãŒã«ç¡æã§ãã¯ãã«ã«ãµããŒããæäŸããããã¹ãã£ã³ã°äºæ¥è ãšé£æºããå Žåãå¥çŽã«åŸã£ãŠãã¹ãã£ã³ã°äºæ¥è ãžã®è¿ä¿¡ãšè«æ±ã«è²»ããããæéãèšé²ãããŸãã
- ã¯ã©ã€ã¢ã³ãã®ãµããŒããç¡æã§ãªãå Žåãè²»çšã¯äŸ¡æ Œè¡šã«åºã¥ããŠåœ¢æãããŸããæéã¯ãè²»ãããæéãŸãã¯æäŸããããµãŒãã¹ã®ãªã¹ãã«ãã£ãŠç°ãªããŸãã ãªã¯ãšã¹ããå®äºãããšããã¹ãã«ä»£ãã£ãŠã¯ã©ã€ã¢ã³ãã«è«æ±ãè¡ãããISPlicenseã¯ãã®å²åãåãåããŸãã
ããã§ãèªååããŒã«ã䜿çšããã«ãµããŒãããã»ã¹ãé 眮ããæ¹æ³ãèããŠã¿ãŸãããã
æåã¯ãããŸããŸãªæ¹æ³ã§é¡§å®¢ãšã®ååãæŽçã§ããŸãã誰ããåŸæ¥å¡ã®ãŠãŒã¶ãŒåãšãã¹ã¯ãŒããå ¥åãã誰ããåã ã®ãŠãŒã¶ãŒãéå§ããBILLmanagerã䜿çšããŠèª°ãã«æ¥ç¶ã§ããŸãã ãã ãããã¹ããããŠãããµãŒããŒã®æ°ãéåžžã«å€ããªãããã¯ãã«ã«ãµããŒããªãã¬ãŒã¿ãŒãå€æ°ã®ãã©ãŠã¶ãŒã¿ãã§æ··ä¹±ããåæã«ãã±ããå ã®æ°ããã¡ãã»ãŒãžã远跡ããå¿ èŠãããå Žåãæ³åããŠãã ããã
ãã®ç¶æ³ãé²ãããã«ãISPlicenseã¯ãBILLmanagerããã³ãã®ä»ã®èª²éã·ã¹ãã ãšçµ±åãããCOREmanagerã«åºã¥ãæè¡ãµããŒãã·ã¹ãã ãéçºããŸããã ãã®è£œåã¯ãTicketManagerãšåŒã°ããŸãã
ããããä»ã COREmanagerã«ã€ããŠããå°ã説æãã䟡å€ããããŸãã ããã¯ãC ++ã§èšè¿°ãããã³ã³ã¹ãã©ã¯ã¿ã§ãã
ãã®éçºã¯2010幎ã«å§ãŸããŸããã COREmanagerã¯ã補åã®äžè¬çãªæ©èœãå¥ã®ãšã³ãã£ãã£ã«çµã¿èŸŒã¿ãã³ã³ããŒãã³ãã®äžè²«æ§ã確ä¿ããããã«äœæãããŸããã BILLmanagerãISPmanagerãVMmanagerãDCImanagerãããã³ãã®ä»ã®ã³ã³ãããŒã«ããã«ã¯ããã«ãŒãã«ãã®æ¡åŒµæ©èœã«ãªããŸãããããã¯ãæãçµéšã®ããISPsysteméçºè ãšã¯å¥ã®ããŒã ã«ãã£ãŠäœæãããŠããŸãã ãã®çµæãéçºæéãççž®ããããã°ã®å¯èœæ§ãæžå°ããæçµè£œåã®é床ãåäžããŸããã
COREmanagerã¯ç¡æã§ããã®äœ¿çšæ¹æ³ã説æãã詳现ãªããã¥ã¡ã³ãããããã»ãŒãã¹ãŠã®ã¿ã¹ã¯ã解決ããããŒã«ã®éçºã«é©çšã§ããŸãã ã¡ãã¥ãŒæ§é ã¯ãWebã€ã³ã¿ãŒãã§ãŒã¹ãä»ããŠããŸãã¯xmlãã¡ã€ã«ãäœæããããšã«ããäœæã§ããŸãããŸãããã®ã€ã³ã¿ãŒããªã¿ãŒããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«ã€ã³ã¹ããŒã«ãããŠããå Žåãä»»æã®ããã°ã©ãã³ã°èšèªã䜿çšããŠã€ãã³ãåŠçã¡ã«ããºã ãå®è£ ã§ããŸãã
ãããã£ãŠãISPlicenseã¯COREmanagerãéžæããŠTicketManagerãäœæããŸããã ã¯ãããã¯ãã«ã«ãµããŒãã«æ¢è£œã®ãœãªã¥ãŒã·ã§ã³ã䜿çšããããBILLmanagerã®ãã©ã°ã€ã³ãäœæããŠåé¡ã解決ãããã§ããŸãããISPlicenseããã°ã©ããŒã¯ãCOREmanagerã§ã§ããããšãèªåã§è©ŠããŠã¿ããã£ãã®ã§ãã :)
ã¢ãŠããœãŒã·ã³ã°ãµãŒãã¹ãéå§ããåŸãæéã®çµéãšãšãã«åé¡è§£æ±ºã®åé¡ã圢ã«ãªãããã¯ãã«ã«ãµããŒãã·ã¹ãã ãéçºããå¿ èŠãçããŸããã 次ã®åæãšã¿ã¹ã¯ã圢æãããŸããã
- ãŠãŒã¶ãŒã«çžè«ããããã«åãããã€ããŒã®ããã«ã«ã¢ã¯ã»ã¹ãããã³ã«æéãããããããŸãã ããã«ããã¯ãã«ã«ãµããŒãã®åŸæ¥å¡ãè€æ°ã®ãããã€ããŒãšé£æºããŠããå ŽåãåŸæ¥å¡ã¯è€æ°ã®ã¿ããŸãã¯ãã©ãŠã¶ãŒãŠã£ã³ããŠãéãå¿ èŠããããããæ··ä¹±ãçããå¯èœæ§ããããŸãã åæã«ããã¹ãã£ã³ã°äºæ¥è ã¯ããŸããŸãªéçºè ããã®è«æ±æžã䜿çšã§ããŸãã ãããã£ãŠããã±ãããããŒã1ã€ã®è£œåã«éçŽããåäžã®ãã¥ãŒã«è¡šç€ºããå¿ èŠããããŸãã
- ãµããŒãã®è«æ±ã¯1æéããšãªã®ã§ããã±ããã«è²»ãããæéã®äŸ¿å©ãªã¢ã«ãŠã³ãã£ã³ã°ãå®è£ ããå¿ èŠããããŸãã
- å©äŸ¿æ§ãšæéã®ç¯çŽã®ããã«ããšã³ããŠãŒã¶ãŒã«æ¥ãã¢ã«ãŠã³ãã®èªåçæãå®è£ ããŸãïŒããšãã°ãææã®ç®¡çã®ããïŒã
- ãã¹ãã£ã³ã°äºæ¥è åãã®ã¬ããŒããšã¢ã«ãŠã³ãã®äœæãèªååããŸãã
- ãããã€ããŒãšISPlicenseã®äž¡æ¹ã«å¯ŸããäžèŠãªè³ªåãé¿ããããã«ããšã³ãã¯ã©ã€ã¢ã³ãã¯ãã¯ãã«ã«ãµããŒããå€éšå§èšãããŠããããšãç¥ããªãããã«ããå¿ èŠããããŸãã
çµæã®è£œåã¯ããã±ããã·ã¹ãã èªäœãšãè«æ±ã¯ã©ã€ã¢ã³ãã«ã€ã³ã¹ããŒã«ããããã³ãã©ãŒã®2ã€ã®éšåã§æ§æãããŸãã å¥ã®ãã¯ãã«ã«ãµããŒãã·ã¹ãã ãŸãã¯èª²éã·ã¹ãã ãšçµ±åã§ããAPIããããŸãã
ãã¯ãã«ã«ãµããŒãããã«ã®äž»èŠãªæ©èœãç解ããŠãã ããã
ãã±ããã®ãªã¹ãã¯æå°éã§ãããã¢ããªã±ãŒã·ã§ã³è¡šç€ºã¡ãã¥ãŒã§ã¢ããªã±ãŒã·ã§ã³ãæäœããããã®ããŒã«ãå©çšã§ããŸãã

äŸã«å¯Ÿããã¢ããŒã«ãéããããã䜿çšããŠå®è¡ã§ããã¢ã¯ã·ã§ã³ã確èªããŸãããã

- è¿ä¿¡ããŸãã ãªãã¬ãŒã¿ãŒã®åŸã«ãã±ããããããã¯ããå¿çå ¥åãã©ãŒã ãéããè²»ãããæéã®ã¢ã«ãŠã³ãã£ã³ã°ãéå§ããŸãã
- ã泚æ ãã®ãªã¯ãšã¹ãã«é¢é£ããååã«ã¡ã¢ãæ®ãããšãã§ããŸãã ãããã€ããŒã«ããšã³ãã¯ã©ã€ã¢ã³ãã«ã衚瀺ãããŸããã
- ãå®¢æ§ ãšã³ãã¯ã©ã€ã¢ã³ãã«æ·»ä»ãããã¡ã¢çšã®å€§ããªããã¹ããã£ãŒã«ããéããŸãã
- ãããžã§ã¯ã ãã¹ãã£ã³ã°äºæ¥è ã®åæ§ã®ãã£ãŒã«ããåŒã³åºããŸãã
- ãéãåŒãåºããŸã ã ãã¹ãã£ã³ã°èª²éã·ã¹ãã ã§ã®ãšã³ãã«ã¹ã¿ããŒããã®ãµãŒãã¹ã®æäŸã«å¯ŸããŠãéãè«æ±ããŸãã
- éããŸãã ãªãŒãã³ãã±ããã®ãªã¹ãã«æ»ããŸãã
ããã«ããŠã£ã³ããŠã«ã¯ãã±ããéå§è ã«é¢ãããã¹ãŠã®æ å ±ã衚瀺ãããŸãã ã¯ã©ã€ã¢ã³ãã®IDãã¯ãªãã¯ãããšãè«æ±ãè¡ãããŸãããµãŒããŒåãã¯ãªãã¯ãããšããã®ãµãŒããŒã®ã³ã³ãããŒã«ããã«ã«ç§»åããŸãã
åŒã³åºãã®åä¿¡ã«é¢é£ãããµãŒãã¹ã«é¢ããæ å ±ã衚瀺ãããã¢ã¯ã»ã¹ããŒã¿ãå«ãããµãŒãã¹ãå±éãããŠãããµãŒããŒã«é¢ããæ å ±ã衚瀺ãããŸãã
ãã±ãããããã¯ããŠãéãããå¿çå ¥åãã©ãŒã ã®ã¢ã¯ãã£ããªèŠçŽ ã確èªããŸãã
- ããã¯è§£é€ ãªãã¬ãŒã¿ãŒãããã±ããã®ãã€ã³ãã解é€ããä»ã®äººãçããåãããšãèš±å¯ããŸãã
- éšé ã ãã¹ãã£ã³ã°ãããã€ããŒã®å¥ã®ãŠãããã«ã¢ããªã±ãŒã·ã§ã³ã転éããŸãã ããšãã°ãæè¡çãªå°é家ããäŒèšãŸã§ã財åäžã®åé¡ã解決ããå Žåã§ãã
- å éšè§£èª¬ ã ã¯ã©ã€ã¢ã³ãããã³ãããã€ããŒããé衚瀺ã«ãªãã¡ãã»ãŒãžããã±ããã«æžã蟌ãããšãã§ããŸãã
- éãããæé ã ãã±ãããžã®å¿çã®æéã æ°åã§æž¬å®ã å€ãæåã§å€æŽãããšãèªåã¿ã€ãã³ã°ãåæ¢ããŸãã
- ã¿ã€ã ã«ãŠã³ã¿ãŒãåæ¢ããŸãã ãªãã¬ãŒã¿ãŒãè¿ãå°æ¥ã«èŠæ±ã解決ããããã®ã¢ã¯ã·ã§ã³ãå®è¡ããªããšæ³å®ãããç¶æ³ã§äœ¿çšãããŸãã ããšãã°ãISPmanagerãå±éããåã®åŸæ¥å¡ã¯ãä»®æ³ãã·ã³ãžã®ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ã€ã³ã¹ããŒã«ãå®äºãããŸã§åŸ æ©ããŸãã
- ã¹ããŒã¿ã¹ ãã±ããã®ã¹ããŒã¿ã¹ã
- éã ãªã¯ãšã¹ãã«å¿ããŠäœæ¥ãé²è¡äžã§ãã
- éåº ãªã¯ãšã¹ããå®äºããŸããã
- ãã®éçšã§ ã èŠæ±ããµãŒãããŒãã£ã«ãã£ãŠå®è¡ãããæäœãé·ããããã»ã¹å¶åŸ¡ãå¿ èŠãªå Žåã«äœ¿çšãããŸãã ãæžã蟌ã¿ãã¿ã¹ã¯ã®éªéã«ãªããªãããã«ãèŠæ±ã¯ãªã¹ãã®äžçªäžã«ãããŸãã
- 延æ ã ãã±ããã¯ãã延æããã£ãŒã«ãã«ç€ºãããæéãçµéãããŸã§äžè¬ãªã¹ãã«è¡šç€ºãããŸããã
- å éšã³ã¡ã³ãããããã€ããŒã«éä¿¡ããŸã ã æžé¢ã¯ãšã³ããŠãŒã¶ãŒã«ã¯è¡šç€ºãããŸãããããã¹ãã£ã³ã°ãããã€ããŒã®åŸæ¥å¡ã«ã¯è¡šç€ºãããŸãã
- ã¯ã©ã€ã¢ã³ãã«ãããã±ããã®ã¯ããŒãºãæåŠããŸã ã åµååé¡ãéæ³è¡çºã解決ãããšãã«äœ¿çšãããŸãã
çžè«äžããšã³ããŠãŒã¶ãŒã¯ISPã®ã©ã€ã»ã³ã¹ã¹ãã·ã£ãªã¹ãã質åã«çããŠããããšãç¥ããŸããã 圌ã¯ãäŒè©±ãèªåã®ãã¹ãã£ã³ã°ãããã€ããŒã®åŸæ¥å¡ãšã®ãã®ã§ãããšèããŠããŸãã
補åã®å®è£ ã«ã¯ããã¯ãã«ã«ãµããŒãããã«ã§çŽ5000è¡ãBILLmanagerããã®ä»ã®èª²éã·ã¹ãã ãšã®çµ±åã¢ãžã¥ãŒã«ã§çŽ500è¡ãå¿ èŠã§ããã
èå³ã®ããæ¹ã¯ãTicketManager API ãããã³ä»¥äžã®ãã¿ãã¬-BILLmanagerã®çµ±åã¢ãžã¥ãŒã«ã®ãœãŒã¹ã³ãŒããã芧ãã ããã
å¿ èŠãªæ©èœã®å€§éšåãCOREmanagerã«æ¢ã«å®è£ ãããŠãããããå¿ èŠãªæ©èœãã³ãŒãã£ã³ã°ãããåäžã®ãªã¹ãã«ãŸãšããããšã«å€ãã®æéãè²»ãããããšãããããŸããã ãŸããã€ã³ã¿ãŒãã§ã€ã¹ããã¿ã³ãé 眮ããå Žæã瀺ãããã ãã«èšè¿°ããå¿ èŠã¯ãããŸããã§ããã
ã¡ã€ã¯ãã¡ã€ã«
MGR = billmgr PLUGIN = ticketmgri VERSION = 5.0.1 LIB += ticketmgri ticketmgri_SOURCES = ticketmgri.cpp WRAPPER += ticketmgri_syncticket ticketmgri_syncticket_SOURCES = ticketmgri_syncticket.cpp ticketmgri_syncticket_LDADD = -lbase BASE ?= /usr/local/mgr5 include $(BASE)/src/isp.mk
billmgr_mod_ticketmgri.xml
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <library name="ticketmgri" /> </mgrdata>
ticketmgri.cpp
#include <api/action.h> #include <api/module.h> #include <api/stdconfig.h> #include <billmgr/db.h> #include <mgr/mgrdb_struct.h> #include <mgr/mgrlog.h> #include <mgr/mgrtask.h> MODULE("ticketmgri"); using namespace isp_api; namespace { StringVector allowedDepartments, hideDepartments; /** * , LongTask ( ) sbin/ticketmgri_syncticket * * [in] _id */ void SyncTicket(int _id) { string id = str::Str(_id); Warning("Sync %s", id.c_str()); if (!_id) return; mgr_task::LongTask("sbin/ticketmgri_syncticket", "ticket_" + id, "ticketmgri_sync") .SetParam(id) .Start(); } /** * * * */ struct eTicketEdit : public Event { /** * * * * * ev , * elid_name . * */ eTicketEdit(const string &ev, const string &elid_name = "elid") : Event(ev, "ticketmgri_" + ev), elid_name_(elid_name) { Warning("eTicketEdit created"); } /** * * * , * [in] ses */ void AfterExecute(Session &ses) const override { Warning("subm %d cb %s elid %s", ses.IsSubmitted(), ses.Param("clicked_button").c_str(), ses.Param("elid").c_str()); string button = ses.Param("clicked_button"); string elid; if (elid_name_ == "elid_ticket2user") { elid = db->Query("SELECT ticket FROM ticket2user WHERE id='" + ses.Param("elid") + "'") ->Str(); } else { elid = ses.Param("elid"); } if ((ses.IsSubmitted() || ses.Param("sv_field") == "ok_message") && (button == "ok" || button == "" || button == "ok_message")) { if (!ses.Has(elid_name_)) { SyncTicket(db->Query("SELECT MAX(id) FROM ticket")->Int()); } else { SyncTicket(str::Int(elid)); } } } string elid_name_; }; /** * , */ struct eClientTicketEdit : public eTicketEdit { eClientTicketEdit() : eTicketEdit("clientticket.edit") {} /** * , , * * , * * [in] ses */ void AfterExecute(Session &ses) const override { eTicketEdit::AfterExecute(ses); for (auto &i : hideDepartments) { ses.xml.RemoveNodes("//slist[@name='client_department']/val[@key='" + i + "']"); } } }; /** * , */ struct aTicketintegrationSetFilter : public Action { aTicketintegrationSetFilter() : Action("ticketintegration.setfilter", MinLevel(lvAdmin)) {} /** * * * * * [in] ses */ void Execute(Session &ses) const override { InternalCall(ses, "account.setfilter", "elid=" + ses.Param("elid")); ses.Ok(ses.okTop); } }; /** * */ struct aTicketintegrationPost : public Action { aTicketintegrationPost() : Action("ticketintegration.post", MinLevel(lvAdmin)) {} void Execute(Session &ses) const override { Execute(ses, true); } /** * * * [in] ses * [in] retry , , * */ void Execute(Session &ses, bool retry) const { auto openTickets = db->Query("SELECT id FROM ticket2user WHERE ticket=" + ses.Param("elid") + " AND user IN (" + str::Join(allowedDepartments, ",") + ")"); string elid; if (openTickets->Eof()) { if (ses.Param("type") == "setstatus" && ses.Param("status") == "closed") { ses.NewNode("ok"); return; } if (retry) { InternalCall(ses, "support_tool_responsible", "set_responsible_default=off&sok=ok&set_responsible=e%5F" + allowedDepartments[0] + "&elid=" + ses.Param("elid")); Execute(ses, false); return; } else { throw mgr_err::Error("cannot_open_ticket"); } } else { elid = openTickets->Str(); } if (ses.Param("type") == "setstatus" && ses.Param("status") == "new") { return; } auto ret2 = InternalCall( ses, "ticket.edit", string() + "sok=ok&show_optional=on" + "&clicked_button=" + (ses.Param("status") == "new" ? "ok_message" : "ok") + "&" + (!ses.Checked("internal") ? "message" : "note_message") + "=" + str::url::Encode(ses.Param("message")) + "&elid=" + elid); // TODO: attachments, sender_name ses.NewNode("ok"); } }; /** * , , */ struct TicketmgriLastNote : public mgr_db::CustomTable { mgr_db::ReferenceField Ticket; mgr_db::ReferenceField LastNote; TicketmgriLastNote() : mgr_db::CustomTable("ticketmgri_last_note"), Ticket(this, "ticket", mgr_db::rtRestrict), LastNote(this, "last_note", "ticket_note", mgr_db::rtRestrict) { Ticket.info().set_primary(); } }; /** * , last_note ticketmgri_last_note */ struct aTicketintegrationLastNote : public Action { aTicketintegrationLastNote() : Action("ticketintegraion.last_note", MinLevel(lvSuper)) {} /** * , last_note * ticketmgri_last_note * * [in] ses */ void Execute(Session &ses) const override { auto t = db->Get<TicketmgriLastNote>(); if (!t->Find(ses.Param("elid"))) { t->New(); t->Ticket = str::Int(ses.Param("elid")); } if (ses.IsSubmitted()) { t->LastNote = str::Int(ses.Param("last_note")); t->Post(); ses.Ok(); } else { ses.NewNode("last_note", t->LastNote); } } }; /** * , , */ struct aTicketintegrationPushTasks : public Action { aTicketintegrationPushTasks() : Action("ticketintegraion.push_tasks", MinLevel(lvSuper)) {} /** * , * * * [in] ses */ void Execute(Session &ses) const override { mgr_xml::XPath xpath = InternalCall("longtask", "filter=yes&state=err&queue=ticketmgri_sync") .GetNodes("//elem[queue='ticketmgri_sync' and status='err']"); for (auto elem : xpath) { auto data = InternalCall("longtask.edit", "elid=" + elem.FindNode("pidfile").Str()); mgr_task::LongTask(data.GetNode("//realname"), data.GetNode("//id"), "ticketmgri_sync") .SetParam(data.GetNode("//params")) .Start(); } } }; /** * */ struct aTicketintegrationGetBalance : public Action { aTicketintegrationGetBalance() : Action("ticketintegration.getbalance", MinLevel(lvAdmin)) {} /** * * * [in] ses */ void Execute(Session &ses) const override { ses.NewNode("balance", InternalCall(ses, "account.edit", "elid=" + ses.Param("elid")) .GetNode("//balance") .Str()); } bool IsModify(const Session &) const override { return false; } }; /** * , */ struct aTicketintegrationDeduct : public Action { aTicketintegrationDeduct() : Action("ticketintegration.deduct", MinLevel(lvAdmin)) {} /** * * * SQL- . * . * , * * [in] ses */ void Execute(Session &ses) const override { auto openTickets = db->Query("SELECT id FROM ticket2user WHERE ticket=" + ses.Param("ticket") + " AND user IN (" + str::Join(allowedDepartments, ",") + ")"); if (openTickets->Eof()) { throw mgr_err::Value("ticket"); } string elid = openTickets->AsString(0); InternalCall(ses, "ticket.edit", "sok=ok&show_optional=on&elid=" + elid + "&ticket_expense=" + ses.Param("amount")); } }; } // namespace // , , // MODULE_INIT(ticketmgri, "") { Warning("Init TICKETmanager integtration"); mgr_cf::AddParam("TicketmgrUrl", "https://tickets.isplicense.ru:1500/ticketmgr"); mgr_cf::AddParam("TicketmgrLogin"); mgr_cf::AddParam("TicketmgrPassword"); mgr_cf::AddParam("TicketmgrBillmgrUrl"); mgr_cf::AddParam("TicketmgrUserId"); mgr_cf::AddParam("TicketmgrAllowedDepartments"); mgr_cf::AddParam("TicketmgrHideDepartments"); str::Split(mgr_cf::GetParam("TicketmgrAllowedDepartments"), ",", allowedDepartments); if (allowedDepartments.empty()) { allowedDepartments.push_back(0); } str::Split(mgr_cf::GetParam("TicketmgrHideDepartments"), ",", hideDepartments); db->Register<TicketmgriLastNote>(); new eClientTicketEdit; new eTicketEdit("ticket.edit", "elid_ticket2user"); new eTicketEdit("support_tool_responsible", "plid"); new aTicketintegrationSetFilter; new aTicketintegrationPost; new aTicketintegrationLastNote; new aTicketintegrationPushTasks; new aTicketintegrationGetBalance; new aTicketintegrationDeduct; }
ticketmgri_syncticket.cpp
#include <billmgr/db.h> #include <billmgr/defines.h> #include <billmgr/sbin_utils.h> #include <ispbin.h> #include <mgr/mgrclient.h> #include <mgr/mgrdb_struct.h> #include <mgr/mgrenv.h> #include <mgr/mgrlog.h> #include <mgr/mgrproc.h> #include <mgr/mgrrpc.h> MODULE("syncticket"); using sbin::DB; using sbin::GetMgrConfParam; using sbin::Client; using sbin::ClientQuery; /** * Ticketmanager * * * */ mgr_client::Client &ticketmgr() { static mgr_client::Client *ret = []() { mgr_client::Remote *ret = new mgr_client::Remote(GetMgrConfParam("TicketmgrUrl")); ret->AddParam("authinfo", GetMgrConfParam("TicketmgrLogin") + ":" + GetMgrConfParam("TicketmgrPassword")); return ret; }(); return *ret; } /** * TICKETmanager * * , xml c , * , , , */ void PostTicket(const string &elid) { // , , auto ticket = DB()->Query("SELECT * FROM ticket WHERE id=" + elid); if (ticket->Eof()) throw mgr_err::Missed("ticket"); auto account = DB()->Query("SELECT * FROM account WHERE id=" + ticket->AsString("account_client")); if (account->Eof()) throw mgr_err::Missed("account"); auto user = DB()->Query("SELECT * FROM user WHERE account=" + account->AsString("id") + " ORDER BY id LIMIT 1"); if (user->Eof()) throw mgr_err::Missed("user"); // xml- mgr_xml::Xml infoXml; auto info = infoXml.GetRoot(); auto customer = info.AppendChild("customer"); customer.AppendChild("id", account->AsString("id")); customer.AppendChild("name", account->AsString("name")); customer.AppendChild("email", user->AsString("email")); customer.AppendChild("phone", user->AsString("phone")); customer.AppendChild("link", GetMgrConfParam("TicketmgrBillmgrUrl") + "?startform=ticketintegration.setfilter&elid=" + account->AsString("id")); if (!ticket->IsNull("item")) { auto item = DB()->Query("SELECT id, name, processingmodule FROM item WHERE id=" + ticket->AsString("item")); if (item->Eof()) throw mgr_err::Missed("item"); auto iteminfo = info.AppendChild("item"); // iteminfo.SetProp("selected", "yes"); iteminfo.AppendChild("id", item->AsString("id")); iteminfo.AppendChild("name", item->AsString("name")); iteminfo.AppendChild("serverid", item->AsString("processingmodule")); // ForEachQuery(DB(), "SELECT intname, value FROM itemparam WHERE item=" + ticket->AsString("item"), i) { if (i->AsString(0) == "ip") { iteminfo.AppendChild("ip", i->AsString(1)); } else if (i->AsString(0) == "username") { iteminfo.AppendChild("login", i->AsString(1)); } else if (i->AsString(0) == "password") { iteminfo.AppendChild("password", i->AsString(1)); } else if (i->AsString(0) == "domain") { iteminfo.AppendChild("domain", i->AsString(1)); } } } // Ticketmanager StringMap args = {{"remoteid", ticket->AsString("id")}, {"department", ticket->AsString("responsible")}, {"info", infoXml.Str()}, {"subject", ticket->AsString("name")}}; ticketmgr().Query("func=clientticket.add&sok=ok", args); } int ISP_MAIN(int ac, char **av) { if (ac != 2) { fprintf(stderr, "Usage: ticketmgri_syncticket ID"); return 1; } string elid = av[1]; try { mgr_log::Init("ticketmgri"); string status = "closed"; int lastmessage = 0; // , string newStatus = DB()->Query("SELECT COUNT(*) FROM ticket2user WHERE ticket=" + elid + " AND user IN (" + GetMgrConfParam("TicketmgrAllowedDepartments") + ")") ->Int() ? "new" : "closed"; bool inDepartment = DB()->Query("SELECT COUNT(*) FROM ticket WHERE id=" + elid + " AND responsible IN (" + GetMgrConfParam("TicketmgrAllowedDepartments") + ")") ->Int(); if (newStatus != "new" && !inDepartment) { LogNote("Skip ticket %s: status=%s, inDepartment=%d", elid.c_str(), newStatus.c_str(), inDepartment); return 0; } try { // Ticketmanager auto r = ticketmgr().Query("func=clientticket.info&remoteid=?", elid); status = r.value("status"); lastmessage = str::Int(r.value("lastmessage")); } catch (mgr_err::Error &e) { if (e.type() == "missed" && e.object() == "remoteid") { // , PostTicket(elid); } else { throw; } } // last_note int lastnote = str::Int(Client() .Query("func=ticketintegraion.last_note&elid=" + elid) .value("last_note")); // auto msg = DB()->Query( string() + "SELECT ticket_message.id, user.realname AS username, user.level AS " "userlevel, message, 1 AS type, ticket_message.date_post " + "FROM ticket_message " + "JOIN user ON ticket_message.user=user.id " + "WHERE ticket_message.id > " + str::Str(lastmessage) + " " + "AND user != " + GetMgrConfParam("TicketmgrUserId") + " " + "AND ticket = " + elid + " " + "UNION " "SELECT ticket_note.id, user.realname AS username, user.level AS " "userlevel, note AS message, 2 AS type, ticket_note.date_post " + "FROM ticket_note " + "JOIN user ON ticket_note.user=user.id " + "WHERE ticket_note.id > " + str::Str(lastnote) + " " + "AND user != " + GetMgrConfParam("TicketmgrUserId") + " " + "AND ticket = " + elid + " " + "ORDER BY date_post"); // , Ticketmanager if (msg->Eof() && status != newStatus) { StringMap params = { {"remoteid", elid}, {"status", newStatus}, }; ticketmgr().Query( "func=clientticket.post&sok=ok&sender=staff&sender_name=System&type=" "setstatus", params); } else { // Ticketmanager lastnote = 0; for (msg->First(); !msg->Eof(); msg->Next()) { StringMap params = { {"remoteid", elid}, {"status", newStatus}, {"sender_name", msg->AsString("username")}, {"sender", msg->AsInt("userlevel") >= 28 ? "staff" : "client"}, {"message", msg->AsString("message")}, }; int attachments = 0; if (msg->AsInt("type") == 1) { params["messageid"] = msg->AsString("id"); // ForEachQuery( DB(), "SELECT * FROM ticket_message_attach WHERE ticket_message=" + msg->AsString("id"), attach) { string id = str::Str(attachments++); auto info = ClientQuery("func=ticket.file&elid=" + attach->AsString("id")); params["attachment_name_" + id] = info.xml.GetNode("//content/name").Str(); params["attachment_content_" + id] = str::base64::Encode( mgr_file::Read(info.xml.GetNode("//content/data").Str())); } } else { lastnote = std::max(lastnote, msg->AsInt("id")); params["internal"] = "on"; } params["attachments"] = str::Str(attachments); ticketmgr().Query("func=clientticket.post&sok=ok&type=message", params); } // last_note if (lastnote) { Client().Query("func=ticketintegraion.last_note&sok=ok&elid=" + elid + "&last_note=" + str::Str(lastnote)); } } } catch (std::exception &e) { fprintf(stderr, "%s\n", e.what()); return 1; } return 0; }
éçºã®çµæãæè¡ãµããŒããªãã¬ãŒã¿ãŒã®äœæ¥ããã䟿å©ã«ãªããããã¥ã¡ã³ãã®èªåçæãä¿èšŒããããšã³ããŠãŒã¶ãŒã®ãªã¯ãšã¹ããããéãåŠçãããããã«ãªããŸããã
ISPlicenseã®ä»åŸã®èšç»ã«ã¯ãæ°ããã¢ããªã±ãŒã·ã§ã³ã®å°çãç¥ããããã¹ã¯ãããããã¢ããªã±ãŒã·ã§ã³ã®å®è£ ãå«ãŸããŸãããŸãã2åã¯ãªãã¯ããã ãã§ç¹å®ã®ãã±ããã«è²»ãããæéã®ã¢ã«ãŠã³ãã£ã³ã°ãåæ¢ããã³åéã§ããŸãã
çµè«ãšããŠãCOREmanagerã¯ãTicketManagerãšãã¹ãŠã®è£œåã®åºç€ã«ãªã£ãã ãã§ã¯ãããŸããã ããã«åºã¥ããŠãå³æžé€šåºéäŒèšã·ã¹ãã ã翻蚳è ãšå¯Ÿè©±ããããã®ãµãŒãã¹ãå ±åæ è¡ãçµç¹ããããã®ããŒã«ããã¹ã¿ãŒã®ããã®ã¿ã¹ã¯èšå®ã·ã¹ãã ãå®è£ ãããŠãããããã¯ãªã¹ãã®ããã4åã®1ã§ãã ã¢ãžã¥ãŒã«ã¯ããµãŒããŒã«ã€ã³ã¹ããŒã«ãããã€ã³ã¿ãŒããªã¿ãŒã䜿çšããŠä»»æã®èšèªã§äœæã§ãããããããžãã¹ã¢ãã«ã«å®å šã«é©åããçã«ãŠããŒã¯ãªè£œåãäœæã§ããŸãã
次ã®èšäºã®1ã€ã§ã¯ãMMOãããžã§ã¯ããäŸãšããŠäœ¿çšããŠãã²ãŒã æ¥çã§ã®COREmanagerã®ã¢ããªã±ãŒã·ã§ã³ã«ã€ããŠèª¬æããŸãããã®ãœãªã¥ãŒã·ã§ã³ã§ã¯ããŠãŒã¶ãŒã¢ã«ãŠã³ãã£ã³ã°ããµãŒããŒç®¡çãåæãããã³ä»ã®å€ãã®ã¿ã¹ã¯ã«äœ¿çšãããŸãã
PS COREmanagerã®è©³çŽ°ãç¥ãããå Žåã¯ãã€ã³ã¹ããŒã«æé ãšè£œåããã¥ã¡ã³ãããããŸã ã