flexbiz-server 12.5.25 → 12.5.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server/controllers/controller.js +3 -3
- package/server/controllers/controllerRPT.js +4 -4
- package/server/controllers/createRouteHandler.js +1 -1
- package/server/controllers/rptCreateRouteHandler.js +1 -1
- package/server/libs/joinData.js +6 -5
- package/server/models/mailaccount.js +2 -2
- package/server/models/productcode.js +2 -0
- package/server/modules/lists/ls-productcode.js +7 -0
- package/server/templates/add-file.html +8 -0
- package/server/templates/add-file.pug +9 -0
- package/server/templates/alert task.html +11 -0
- package/server/templates/alert task.pug +12 -0
- package/server/templates/alert warranty.html +15 -0
- package/server/templates/alert warranty.pug +28 -0
- package/server/templates/excels/PN9.xlsx +0 -0
- package/server/templates/excels/hd1.xlsx +0 -0
- package/server/templates/excels/hd2.xlsx +0 -0
- package/server/templates/excels/hd3.xlsx +0 -0
- package/server/templates/excels/lists/account.xlsx +0 -0
- package/server/templates/excels/lists/customer.xlsx +0 -0
- package/server/templates/excels/lists/dmvt.xlsx +0 -0
- package/server/templates/excels/pc1.xlsx +0 -0
- package/server/templates/excels/pkc.xlsx +0 -0
- package/server/templates/excels/pkh.xlsx +0 -0
- package/server/templates/excels/pkt.xlsx +0 -0
- package/server/templates/excels/pn1.xlsx +0 -0
- package/server/templates/excels/pn2.xlsx +0 -0
- package/server/templates/excels/pn3.xlsx +0 -0
- package/server/templates/excels/pn5.xlsx +0 -0
- package/server/templates/excels/pnk.xlsx +0 -0
- package/server/templates/excels/pt1.xlsx +0 -0
- package/server/templates/excels/pxc.xlsx +0 -0
- package/server/templates/excels/pxk.xlsx +0 -0
- package/server/templates/excels/reports/bangtinhkhauhao.xlsx +0 -0
- package/server/templates/excels/reports/bcdkt.xlsx +0 -0
- package/server/templates/excels/reports/bkct.xlsx +0 -0
- package/server/templates/excels/reports/bkvatra.xlsx +0 -0
- package/server/templates/excels/reports/bkvatvao.xlsx +0 -0
- package/server/templates/excels/reports/cdpsdt.xlsx +0 -0
- package/server/templates/excels/reports/cdpskh.xlsx +0 -0
- package/server/templates/excels/reports/cdpstk.xlsx +0 -0
- package/server/templates/excels/reports/chitietchitientheohoadon.xlsx +0 -0
- package/server/templates/excels/reports/chitiettaisan.xlsx +0 -0
- package/server/templates/excels/reports/chitietthutientheohoadon.xlsx +0 -0
- package/server/templates/excels/reports/ctbanle.xlsx +0 -0
- package/server/templates/excels/reports/cthangbanbitralai.xlsx +0 -0
- package/server/templates/excels/reports/ctmuahang.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheokh.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheonam.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheongay.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheonv.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheoquy.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheothang.xlsx +0 -0
- package/server/templates/excels/reports/dtbanletheovt.xlsx +0 -0
- package/server/templates/excels/reports/hangbanbitralai.xlsx +0 -0
- package/server/templates/excels/reports/hoadonbanhangtheohantt.xlsx +0 -0
- package/server/templates/excels/reports/hoadonmuahangtheohantt.xlsx +0 -0
- package/server/templates/excels/reports/kqhdkd.xlsx +0 -0
- package/server/templates/excels/reports/lcttgt.xlsx +0 -0
- package/server/templates/excels/reports/lctttt.xlsx +0 -0
- package/server/templates/excels/reports/pttct.xlsx +0 -0
- package/server/templates/excels/reports/sctcnkh.xlsx +0 -0
- package/server/templates/excels/reports/sctdt.xlsx +0 -0
- package/server/templates/excels/reports/scttk.xlsx +0 -0
- package/server/templates/excels/reports/sctvt.xlsx +0 -0
- package/server/templates/excels/reports/socaitk.xlsx +0 -0
- package/server/templates/excels/reports/sochut.xlsx +0 -0
- package/server/templates/excels/reports/sonkbh.xlsx +0 -0
- package/server/templates/excels/reports/sonkc.xlsx +0 -0
- package/server/templates/excels/reports/sonkct.xlsx +0 -0
- package/server/templates/excels/reports/sonkmh.xlsx +0 -0
- package/server/templates/excels/reports/sonktt.xlsx +0 -0
- package/server/templates/excels/reports/soquy.xlsx +0 -0
- package/server/templates/excels/reports/sotaisan.xlsx +0 -0
- package/server/templates/excels/reports/sotiengui.xlsx +0 -0
- package/server/templates/excels/reports/thnxt.xlsx +0 -0
- package/server/templates/excels/reports/tkgtgt.xlsx +0 -0
- package/server/templates/excels/reports/tonghopbanhang.xlsx +0 -0
- package/server/templates/excels/reports/tonghopmuahang.xlsx +0 -0
- package/server/templates/excels/reports/tonghoptralaihang.xlsx +0 -0
- package/server/templates/imports/cdkh.xlsx +0 -0
- package/server/templates/imports/cdtk.xlsx +0 -0
- package/server/templates/imports/cdvt.xlsx +0 -0
- package/server/templates/imports/contract.xlsx +0 -0
- package/server/templates/imports/dmban.xlsx +0 -0
- package/server/templates/imports/dmkh.xlsx +0 -0
- package/server/templates/imports/dmvt.xlsx +0 -0
- package/server/templates/imports/hd1.xlsx +0 -0
- package/server/templates/imports/hd2.xlsx +0 -0
- package/server/templates/imports/lienhe.xlsx +0 -0
- package/server/templates/imports/pc1.xlsx +0 -0
- package/server/templates/imports/pkt.xlsx +0 -0
- package/server/templates/imports/pn1.xlsx +0 -0
- package/server/templates/imports/pn2.xlsx +0 -0
- package/server/templates/imports/pnk.xlsx +0 -0
- package/server/templates/imports/pt1.xlsx +0 -0
- package/server/templates/order.html +42 -0
- package/server/templates/order.pug +57 -0
- package/server/templates/product-verify-result.ejs +230 -0
- package/server/templates/reply-comment.html +10 -0
- package/server/templates/reply-comment.pug +12 -0
- package/server/templates/reset mat khau.html +17 -0
- package/server/templates/reset mat khau.pug +18 -0
- package/server/templates/thong tin dang nhap.html +15 -0
- package/server/templates/thong tin dang nhap.pug +18 -0
- package/server/templates/thu moi gia nhap nhom.html +14 -0
- package/server/templates/thu moi gia nhap nhom.pug +18 -0
package/package.json
CHANGED
|
@@ -10,9 +10,9 @@ fields:["tg_tk","kg_kiem_tra_ton_kho","kg_kiem_tra_ton_kho_tt",{cb:"combo"},"ten
|
|
|
10
10
|
return $c$$}):[$detail$$]).reduce(($a$$,$b$$)=>$a$$.concat($b$$),[]);await $details$$.asyncJoinModel2($appInfo$$._id,dmqddvt,{where:{ma_vt:"ma_vt",ma_dvt:"ma_dvt"},fields:"ty_le_qd"});let $data_sokho$$=[];$data$$._id&&($data_sokho$$=await global.getModel("sokho").find({id_ct:$data$$._id.toString()}).lean());$details$$.forEach($d$$=>{$d$$.he_so_qd=$d$$.ty_le_qd||1;$d$$.sl_xuat_qd=$d$$.he_so_qd*$d$$.sl_xuat});$details$$=await $details$$.asyncGroupBy(["ma_vt","ma_kho","ten_vt"],["sl_xuat_qd"]);async.map($details$$,
|
|
11
11
|
($d$$,$callback$$)=>{let $ma_kho$$=$d$$.ma_kho||$data$$.ma_kho||$data$$.ma_kho_x,$query$$={ma_vt:$d$$.ma_vt,ma_kho:$ma_kho$$,ngay:new Date,id_app:$appInfo$$._id};$d$$.kg_kiem_tra_ton_kho_tt||($d$$.ma_lo&&($query$$.ma_lo=$d$$.ma_lo),$d$$.han_sd&&($query$$.han_sd=$d$$.han_sd),$d$$.ma_tt1&&($query$$.ma_tt1=$d$$.ma_tt1),$d$$.ma_tt2&&($query$$.ma_tt2=$d$$.ma_tt2),$d$$.ma_tt3&&($query$$.ma_tt3=$d$$.ma_tt3));ckvt($query$$,function($e$$,$rs$$){if($e$$)return $callback$$($e$$);$rs$$?($e$$=$rs$$.csum("ton"),
|
|
12
12
|
$rs$$=$data_sokho$$.filter($s$$=>$s$$.ma_vt===$d$$.ma_vt&&$s$$.ma_kho===$ma_kho$$).reduce(($a$$,$b$$)=>($a$$.sl_xuat_qd||0)+($b$$.sl_xuat_qd||0),0),$d$$.sl_xuat_qd>utils.round($e$$+$rs$$,2)?$callback$$(`S\u1ea3n ph\u1ea9m ${$d$$.ma_vt} - ${$d$$.ten_vt} c\u00f3 s\u1ed1 l\u01b0\u1ee3ng xu\u1ea5t quy \u0111\u1ed5i (${$d$$.sl_xuat_qd}) l\u1edbn h\u01a1n s\u1ed1 l\u01b0\u1ee3ng t\u1ed3n quy \u0111\u1ed5i (${$e$$+$rs$$})`):$callback$$()):$callback$$()})},$e$$=>{$callback$$($e$$)})})():$callback$$()}},$e$$=>
|
|
13
|
-
{$fn$$($e$$)})}async cacheData($obj$$,$callback$$){$obj$$&&$obj$$.toObject&&($obj$$=utils.convertObjectIdsToStrings($obj$$.toObject()));await redisCache.set(this.model_name,$obj$$,$callback$$)}async deleteData($obj$$,$callback$$){$obj$$&&$obj$$.toObject&&($obj$$=utils.convertObjectIdsToStrings($obj$$.toObject()));await redisCache.remove(this.model_name,$obj$$,$callback$$)}createRoute($routeName$$,$handler_routeAction$$,$_options$$={method:"GET",not_use_worker:!1}){const $self$$=
|
|
14
|
-
|
|
15
|
-
{handler:"createRouteHandler",routeName:$routeName$$,_options:$_options$$,route_action_key:$route_action_key$$,query:$query$$,body:$body$$,user:$user$$,params:$params$$,headers:$headers$$,user_agent:$user_agent$$,ip:$ip$$,files:$files$$,originalUrl:$req$$.originalUrl};global.inputMainPool&&!$_options$$.not_use_worker?global.inputMainPool.exec({req:$_req$$,module:$self$$.name.toUpperCase(),configs:JSON.stringify(configs)},$response$$=>{if($response$$.error)return $res$$.status(400).send({error:$response$$.error.error||
|
|
13
|
+
{$fn$$($e$$)})}async cacheData($obj$$,$callback$$){$obj$$&&$obj$$.toObject&&($obj$$=utils.convertObjectIdsToStrings($obj$$.toObject()));await redisCache.set(this.model_name,$obj$$,$callback$$)}async deleteData($obj$$,$callback$$){$obj$$&&$obj$$.toObject&&($obj$$=utils.convertObjectIdsToStrings($obj$$.toObject()));await redisCache.remove(this.model_name,$obj$$,$callback$$)}createRoute($routeName$$,$handler_routeAction$$,$_options$$={method:"GET",not_use_worker:!1,right_code:"view"}){const $self$$=
|
|
14
|
+
this;$_options$$.method=$_options$$.method?$_options$$.method.toUpperCase():"GET";const $route_action_key$$=`route_action_${$self$$.name}_${$routeName$$}_${$_options$$.method}`;$self$$[$route_action_key$$]=$handler_routeAction$$;$handler_routeAction$$=async function($req$$,$res$$){const {query:$query$$,body:$body$$,user:$user$$,params:$params$$,headers:$headers$$,files:$files$$}=$req$$,$user_agent$$=$req$$.header("user-agent"),$ip$$=$req$$.ip||$req$$.headers["x-forwarded-for"]||$req$$.connection.remoteAddress;
|
|
15
|
+
try{const $_req$$={handler:"createRouteHandler",routeName:$routeName$$,_options:$_options$$,route_action_key:$route_action_key$$,query:$query$$,body:$body$$,user:$user$$,params:$params$$,headers:$headers$$,user_agent:$user_agent$$,ip:$ip$$,files:$files$$,originalUrl:$req$$.originalUrl};global.inputMainPool&&!$_options$$.not_use_worker?global.inputMainPool.exec({req:$_req$$,module:$self$$.name.toUpperCase(),configs:JSON.stringify(configs)},$response$$=>{if($response$$.error)return $res$$.status(400).send({error:$response$$.error.error||
|
|
16
16
|
$response$$.error.message||$response$$.error,message:$response$$.message||$response$$.error.error||$response$$.error.message||$response$$.error});$res$$.send($response$$.result)}):handlers.createRouteHandler($self$$,$_req$$,($e$$,$rs$$)=>{if($e$$)return $res$$.status(400).send($e$$);$res$$.send($rs$$)})}catch($e$$){$res$$.status(400).send($e$$)}};let $url$$=`${this.route_name}/${$routeName$$}`,$router$$=this.router;$_options$$.method=="DELETE"?$router$$.route($url$$).delete($handler_routeAction$$):
|
|
17
17
|
$_options$$.method=="POST"?$router$$.route($url$$).post($handler_routeAction$$):$_options$$.method=="PUT"?$router$$.route($url$$).put($handler_routeAction$$):$router$$.route($url$$).get($handler_routeAction$$)}async requestApprove($app_info_listinfo_code$$,$user_request$$,$obj_request$$,$next$$,$str_func$jscomp$2_str_func$$,$preRequest$$){let $ctrl$$=this;if(!$app_info_listinfo_code$$)return $next$$(null,$obj_request$$);let $obj$$;$obj$$=$obj_request$$.toObject?utils.convertObjectIdsToStrings($obj_request$$.toObject()):
|
|
18
18
|
_.cloneDeep($obj_request$$);$obj$$.ma_ct=$obj$$.ma_ct||$ctrl$$.name;let $approveDatas$$=[];$app_info_listinfo_code$$=$obj$$.listinfo_code||$ctrl$$.name;$str_func$jscomp$2_str_func$$||($str_func$jscomp$2_str_func$$=(await OptionsModel.findOne({id_app:$obj$$.id_app,id_func:$app_info_listinfo_code$$},{option:1}).lean()||{}).option);$str_func$jscomp$2_str_func$$&&$str_func$jscomp$2_str_func$$.custom_approve_user&&$str_func$jscomp$2_str_func$$.custom_approve_user.forEach($trang_thai_approve$$=>{let $update_after_approve$$,
|
|
@@ -24,8 +24,8 @@ $res$$.setHeader("Content-Length",$data$jscomp$2_data$jscomp$3_response$jscomp$3
|
|
|
24
24
|
$res$$.end($data$jscomp$4_data$jscomp$5_returnvalue$$);break;case "docx":$res$$.setHeader("Content-Type","application/vnd.openxmlformats-officedocument.wordprocessingml.document");$res$$.setHeader("Content-Disposition",'attachment; filename="'+$rptId$$+'".docx');$data$jscomp$4_data$jscomp$5_returnvalue$$=$e$jscomp$7_result$$;$data$jscomp$4_data$jscomp$5_returnvalue$$?.type==="Buffer"&&Array.isArray($data$jscomp$4_data$jscomp$5_returnvalue$$.data)&&($data$jscomp$4_data$jscomp$5_returnvalue$$=Buffer.from($data$jscomp$4_data$jscomp$5_returnvalue$$.data));
|
|
25
25
|
$res$$.setHeader("Content-Length",$data$jscomp$4_data$jscomp$5_returnvalue$$.length);$res$$.end($data$jscomp$4_data$jscomp$5_returnvalue$$);break;default:$res$$.send($e$jscomp$7_result$$)}})}catch($e$$){$res$$.status(400).send($e$$)}};$router$$.route(`${this.base_path+this.module}`).get($mainRoute$$);$router$$.route(`${this.base_path+this.module}`).post($mainRoute$$);$router$$.route(`${this.base_path+this.module}/excel`).get($excelRoute$$);$router$$.route(`${this.base_path+this.module}/excel`).post($excelRoute$$)}getData($req$$,
|
|
26
26
|
$callback$$){const $ctrl$$=this;let $callback_run$$=!1;setImmediate(()=>{try{$ctrl$$.fecthDataFunc($req$$,($err$$,$data$$,$event$$)=>{if($ctrl$$.options?.stream){if($err$$)return $callback$$($err$$);$event$$!="data"||$callback_run$$||($callback_run$$=!0,this.handleResult($req$$,{error:$err$$,result:$data$$},($e$$,$rs$$)=>{$callback$$($e$$,$rs$$)}))}else $callback_run$$=!0,this.handleResult($req$$,{error:$err$$,result:$data$$},($e$$,$rs$$)=>{$callback$$($e$$,$rs$$)})})}catch($e$$){console.error("[report controller] [getData]",
|
|
27
|
-
$e$$),$callback$$($e$$.message)}})}createRoute($routeName$$,$callbackRoute_handler$$,$_options$$={method:"GET",not_use_worker:!1}){const $self$$=this;$_options$$.method=$_options$$.method?$_options$$.method.toUpperCase():"GET";const $route_action_key$$=`rpt_route_action_${$self$$.module}_${$routeName$$}_${$_options$$.method}`;$self$$[$route_action_key$$]=$callbackRoute_handler$$;$callbackRoute_handler$$=async function($ip$jscomp$2_req$$,$res$$){const {query:$query$$,body:$body$$,
|
|
28
|
-
files:$files$$}=$ip$jscomp$2_req$$;var $_req$jscomp$2_user_agent$$=$ip$jscomp$2_req$$.header("user-agent");$ip$jscomp$2_req$$=$ip$jscomp$2_req$$.ip||$ip$jscomp$2_req$$.headers["x-forwarded-for"]||$ip$jscomp$2_req$$.connection.remoteAddress;try{if($_req$jscomp$2_user_agent$$={handler:"rptCreateRouteHandler",routeName:$routeName$$,_options:$_options$$,route_action_key:$route_action_key$$,query:$query$$,body:$body$$,user:$user$$,params:$params$$,user_agent:$_req$jscomp$2_user_agent$$,
|
|
29
|
-
files:$files$$},!global.reportMainPool||global.reportMainPool.fullQueue()||$_options$$.not_use_worker)handlers.rptCreateRouteHandler(this,$_req$jscomp$2_user_agent$$,($e$$,$returnvalue$$)=>{if($e$$)return $res$$.status(400).send($e$$);$res$$.send($returnvalue$$)});else{const $id_task$$=`report-create-route-${crypto.randomBytes(20).toString("hex")}`;global.reportMainPool.exec({id_task:$id_task$$,req:$_req$jscomp$2_user_agent$$,module:$self$$.module.toUpperCase(),configs:JSON.stringify(configs)}
|
|
30
|
-
{if($response$jscomp$6_result$$.error)return $res$$.status(400).send($response$jscomp$6_result$$.error);({result:$response$jscomp$6_result$$}=$response$jscomp$6_result$$);$res$$.send($response$jscomp$6_result$$)})}}catch($e$$){$res$$.status(400).send($e$$)}};$_options$$.method=="DELETE"?this.router.route(`${this.base_path+this.module}/${$routeName$$}`).delete($callbackRoute_handler$$):$_options$$.method=="POST"?this.router.route(`${this.base_path+this.module}/${$routeName$$}`).post($callbackRoute_handler$$):
|
|
27
|
+
$e$$),$callback$$($e$$.message)}})}createRoute($routeName$$,$callbackRoute_handler$$,$_options$$={method:"GET",not_use_worker:!1,right_code:"view"}){const $self$$=this;$_options$$.method=$_options$$.method?$_options$$.method.toUpperCase():"GET";const $route_action_key$$=`rpt_route_action_${$self$$.module}_${$routeName$$}_${$_options$$.method}`;$self$$[$route_action_key$$]=$callbackRoute_handler$$;$callbackRoute_handler$$=async function($ip$jscomp$2_req$$,$res$$){const {query:$query$$,body:$body$$,
|
|
28
|
+
user:$user$$,params:$params$$,files:$files$$}=$ip$jscomp$2_req$$;var $_req$jscomp$2_user_agent$$=$ip$jscomp$2_req$$.header("user-agent");$ip$jscomp$2_req$$=$ip$jscomp$2_req$$.ip||$ip$jscomp$2_req$$.headers["x-forwarded-for"]||$ip$jscomp$2_req$$.connection.remoteAddress;try{if($_req$jscomp$2_user_agent$$={handler:"rptCreateRouteHandler",routeName:$routeName$$,_options:$_options$$,route_action_key:$route_action_key$$,query:$query$$,body:$body$$,user:$user$$,params:$params$$,user_agent:$_req$jscomp$2_user_agent$$,
|
|
29
|
+
ip:$ip$jscomp$2_req$$,files:$files$$},!global.reportMainPool||global.reportMainPool.fullQueue()||$_options$$.not_use_worker)handlers.rptCreateRouteHandler(this,$_req$jscomp$2_user_agent$$,($e$$,$returnvalue$$)=>{if($e$$)return $res$$.status(400).send($e$$);$res$$.send($returnvalue$$)});else{const $id_task$$=`report-create-route-${crypto.randomBytes(20).toString("hex")}`;global.reportMainPool.exec({id_task:$id_task$$,req:$_req$jscomp$2_user_agent$$,module:$self$$.module.toUpperCase(),configs:JSON.stringify(configs)},
|
|
30
|
+
$response$jscomp$6_result$$=>{if($response$jscomp$6_result$$.error)return $res$$.status(400).send($response$jscomp$6_result$$.error);({result:$response$jscomp$6_result$$}=$response$jscomp$6_result$$);$res$$.send($response$jscomp$6_result$$)})}}catch($e$$){$res$$.status(400).send($e$$)}};$_options$$.method=="DELETE"?this.router.route(`${this.base_path+this.module}/${$routeName$$}`).delete($callbackRoute_handler$$):$_options$$.method=="POST"?this.router.route(`${this.base_path+this.module}/${$routeName$$}`).post($callbackRoute_handler$$):
|
|
31
31
|
$_options$$.method=="PUT"?this.router.route(`${this.base_path+this.module}/${$routeName$$}`).put($callbackRoute_handler$$):this.router.route(`${this.base_path+this.module}/${$routeName$$}`).get($callbackRoute_handler$$)}}module.exports=controllerRPT;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const permission=require("../libs/permission"),{ERRORS}=require("./controllerUtils"),createRouteHandler=async($ctrl$$,$req$$,$callback$$)=>{let $res_send$$=!1;const {routeName:$routeName$$,route_action_key:$route_action_key$$,_options:$_options$$}=$req$$;if($ctrl$$.require_id_app===!1)try{$ctrl$$[$route_action_key$$]($req$$,function($e$$,$rs$$){if($res_send$$)return console.error("route",$routeName$$,"sent header. callback had call");if($e$$){console.error("create route",$routeName$$,$e$$);if($e$$.error)return $res_send$$=
|
|
2
|
-
!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return console.error("route",$routeName$$,$e$$),$res_send$$=!0,$callback$$({error:$e$$.message||$e$$})}else{let $id_app$$=$req$$.params.id_app,$notNeedRight$$=$_options$$.notNeedRight||await $ctrl$$.notNeedRight($req$$.user);permission.hasRight($id_app$$,$req$$.user.email,$ctrl$$.module
|
|
2
|
+
!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return console.error("route",$routeName$$,$e$$),$res_send$$=!0,$callback$$({error:$e$$.message||$e$$})}else{let $id_app$$=$req$$.params.id_app,$notNeedRight$$=$_options$$.notNeedRight||await $ctrl$$.notNeedRight($req$$.user);permission.hasRight($id_app$$,$req$$.user.email,$ctrl$$.module,$_options$$?.right_code||"view",function($error$$,$hr$$){if($res_send$$)return console.error("route",
|
|
3
3
|
$routeName$$,"sent header. hasRight had call");if($hr$$)try{$ctrl$$[$route_action_key$$]($req$$,function($e$$,$rs$$){$res_send$$&&console.error("route",$routeName$$,"sent header. callback had call");if($e$$){if($e$$.error)return $res_send$$=!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return $res_send$$=!0,console.error("route",$routeName$$,$e$$),$callback$$({error:$e$$.message||$e$$})}else return $res_send$$=
|
|
4
4
|
!0,$callback$$({error:$error$$.error||$error$$||ERRORS.ERR_NOT_PERMIT,code:$error$$.code||ERRORS.ERR_NOT_PERMIT_CODE})},{notNeedRight:$notNeedRight$$})}};module.exports=createRouteHandler;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const permission=require("../libs/permission"),createRouteHandler=async($ctrl$$,$req$$,$callback$$)=>{const {routeName:$routeName$$,route_action_key:$route_action_key$$,_options:$_options$$}=$req$$;let $notNeedRight$$=$_options$$.notNeedRight||await $ctrl$$.notNeedRight($req$$.user),$res_send$$=!1;if($ctrl$$.options.require_id_app===!1)try{$ctrl$$[$route_action_key$$]($req$$,function($e$$,$rs$$){if($res_send$$)return console.error("no id_app route",$routeName$$,"sent header. calback had call");if($e$$){console.error("handle create route ",
|
|
2
|
-
$routeName$$,$e$$);if($e$$.error)return $res_send$$=!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return $res_send$$=!0,$callback$$({error:$e$$.message||$e$$})}else permission.hasRight($req$$.params.id_app,$req$$.user.email,$ctrl$$.module
|
|
2
|
+
$routeName$$,$e$$);if($e$$.error)return $res_send$$=!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return $res_send$$=!0,$callback$$({error:$e$$.message||$e$$})}else permission.hasRight($req$$.params.id_app,$req$$.user.email,$ctrl$$.module,$_options$$?.right_code||"view",function($error$$,$hr$$){if($res_send$$)return console.error("route",$routeName$$,"sent header. hasRight had call");if($hr$$)try{$ctrl$$[$route_action_key$$]($req$$,
|
|
3
3
|
function($e$$,$rs$$){if($res_send$$)return console.error("route",$routeName$$,"sent header. calback had call");if($e$$){console.error("handle create route ",$routeName$$,$e$$);if($e$$.error)return $res_send$$=!0,$callback$$($e$$);$res_send$$=!0;return $callback$$({error:$e$$.message||$e$$})}$res_send$$=!0;return $callback$$(null,$rs$$)})}catch($e$$){return $callback$$({error:$e$$.message||$e$$})}else $res_send$$=!0,$callback$$({error:"B\u1ea1n kh\u00f4ng c\u00f3 quy\u1ec1n xem b\u00e1o c\u00e1o n\u00e0y"})},
|
|
4
4
|
{notNeedRight:$notNeedRight$$})};module.exports=createRouteHandler;
|
package/server/libs/joinData.js
CHANGED
|
@@ -27,11 +27,12 @@ $newBatchCacheKey_val$$}else $remainingManualQueries$$.push($mq$$)});$manualQuer
|
|
|
27
27
|
function mergeFields($plan$$,$newFields$$){$plan$$.fields!==null&&($newFields$$===void 0?$plan$$.fields=null:($plan$$.fields?Object.assign($plan$$.fields,$newFields$$):$plan$$.fields={...$newFields$$},$plan$$.dynamicKey&&($plan$$.fields[$plan$$.dynamicKey]=1)))}
|
|
28
28
|
async function executeQueries($batchPlan$$,$manualQueries$$,$options$$,$id_app$$){const $fetchedCache$$={};await runWithoutSession(async()=>{const $promises$$=[];Object.values($batchPlan$$).forEach($plan$$=>{const $values$$=Array.from($plan$$.values).filter($v$$=>$v$$!=null);$values$$.length&&$promises$$.push((async()=>{try{const $modelName$$=$plan$$.model.modelName,$isCacheEnabled$$=$options$$.cache&&cachedKeys&&cachedKeys[$modelName$$];let $missingValues$$=[...$values$$];if($isCacheEnabled$$&&global.clientRedis){const $redisMap$$=
|
|
29
29
|
$values$$.map($val$$=>{var $rKey_tempQ$$={...$plan$$.staticQuery};$rKey_tempQ$$[$plan$$.dynamicKey]=$val$$;$rKey_tempQ$$=generateRedisKey($modelName$$,$rKey_tempQ$$,$id_app$$);return{val:$val$$,rKey:$rKey_tempQ$$}}),$keysToGet$$=$redisMap$$.map($i$$=>$i$$.rKey),$results$$=await redisMGet($keysToGet$$)||[];$missingValues$$=[];$results$$.forEach(($jsonStr$$,$i$$)=>{$i$$=$redisMap$$[$i$$].val;if($jsonStr$$)try{const $data$$=JSON.parse($jsonStr$$);$data$$._id&&($data$$._id=$data$$._id.toString());const $cacheKey$$=
|
|
30
|
-
`${$plan$$.signature}_VAL_${$i$$==null?"__NULL__":$plan$$.dynamicKey==="_id"?$i$$.toString():$i$$}`.replace(/\./g,"_");$fetchedCache$$[$cacheKey$$]=$data$$}catch($e$$){console.
|
|
31
|
-
$id_app$$&&$plan$$.model.schema.paths.id_app&&($query$$.id_app=$id_app$$);let $mq$$=$plan$$.model.find($query$$);$plan$$.fields&&($mq$$=$mq$$.select($plan$$.fields));let $dbResults$$;try{$dbResults$$=await $mq$$.lean()}catch($e$$){throw console.error("[joinData] Batch Error with query:",JSON.stringify($query$$,null,2)),$e$$;}$dbResults$$.forEach($row$$=>{$row$$._id&&($row$$._id=$row$$._id.toString());var $cacheKey$jscomp$4_val$$=$row$$[$plan$$.dynamicKey];$cacheKey$jscomp$4_val$$=`${$plan$$.signature}_VAL_${$cacheKey$jscomp$4_val$$==
|
|
32
|
-
null?"__NULL__":$plan$$.dynamicKey==="_id"?$cacheKey$jscomp$4_val$$.toString():$cacheKey$jscomp$4_val$$}`.replace(/\./g,"_");$fetchedCache$$[$cacheKey$jscomp$4_val$$]=$row$$})}}catch($e$$){console.error("[joinData] Batch Error:",$e$$.message)}})())});const $pendingRequests$$=new Map;$manualQueries$$.forEach($mq$$=>{const $key$$=$mq$$.cacheKey;if($pendingRequests$$.has($key$$))$promises$$.push($pendingRequests$$.get($key$$));else{var $executionPromise$$=(async()=>{try{let $data$$=null;if($options$$.cache&&
|
|
33
|
-
cachedKeys&&cachedKeys[$mq$$.modelName]&&global.clientRedis){const $jsonStr$$=await redisGet($mq$$.cacheKey);if($jsonStr$$)try{$data$$=JSON.parse($jsonStr$$)}catch($e$$){console.warn("JSON parse error from Redis:",$mq$$.cacheKey)}}if(!$data$$)
|
|
34
|
-
$fetchedCache$$[$mq$$.cacheKey]=$data$$):$fetchedCache$$[$mq$$.cacheKey]=null}catch($e$$){console.error("[joinData][executeQueries] Manual Query Error:",$e$$),$fetchedCache$$[$mq$$.cacheKey]=null}finally{$pendingRequests$$.delete($key$$)}})()
|
|
30
|
+
`${$plan$$.signature}_VAL_${$i$$==null?"__NULL__":$plan$$.dynamicKey==="_id"?$i$$.toString():$i$$}`.replace(/\./g,"_");$fetchedCache$$[$cacheKey$$]=$data$$}catch($e$$){console.warn("\u26a0\ufe0f [joinData] parse d\u1eef li\u1ec7u t\u1eeb redis",$e$$),$missingValues$$.push($i$$)}else $missingValues$$.push($i$$)})}$plan$$.dynamicKey==="_id"&&($missingValues$$=$missingValues$$.filter($m$$=>isValidObjectId($m$$)));if($missingValues$$.length){const $query$$={...$plan$$.staticQuery,[$plan$$.dynamicKey]:{$in:$missingValues$$}};
|
|
31
|
+
$id_app$$&&$plan$$.model.schema.paths.id_app&&($query$$.id_app=$id_app$$);let $mq$$=$plan$$.model.find($query$$);$plan$$.fields&&($mq$$=$mq$$.select($plan$$.fields));let $dbResults$$;try{$dbResults$$=await $mq$$.lean()}catch($e$$){throw console.error("\u274c[joinData] Batch Error with query:",JSON.stringify($query$$,null,2)),$e$$;}$dbResults$$.forEach($row$$=>{$row$$._id&&($row$$._id=$row$$._id.toString());var $cacheKey$jscomp$4_val$$=$row$$[$plan$$.dynamicKey];$cacheKey$jscomp$4_val$$=`${$plan$$.signature}_VAL_${$cacheKey$jscomp$4_val$$==
|
|
32
|
+
null?"__NULL__":$plan$$.dynamicKey==="_id"?$cacheKey$jscomp$4_val$$.toString():$cacheKey$jscomp$4_val$$}`.replace(/\./g,"_");$fetchedCache$$[$cacheKey$jscomp$4_val$$]=$row$$})}}catch($e$$){console.error("\u274c[joinData] Batch Error:",$e$$.message)}})())});const $pendingRequests$$=new Map;$manualQueries$$.forEach($mq$$=>{const $key$$=$mq$$.cacheKey;if($pendingRequests$$.has($key$$))$promises$$.push($pendingRequests$$.get($key$$));else{var $executionPromise$$=(async()=>{try{let $data$$=null;if($options$$.cache&&
|
|
33
|
+
cachedKeys&&cachedKeys[$mq$$.modelName]&&global.clientRedis){const $jsonStr$$=await redisGet($mq$$.cacheKey);if($jsonStr$$)try{$data$$=JSON.parse($jsonStr$$)}catch($e$$){console.warn("\u26a0\ufe0f [joinData][executeQueries][manualQueries] JSON parse error from Redis:",$mq$$.cacheKey)}}if(!$data$$)if(Object.values($mq$$.query).filter($v$$=>$v$$===void 0||$v$$===null).length>0)console.warn("\u26a0\ufe0f [joinData][executeQueries][manualQueries]",$mq$$.model.modelName,": query kh\u00f4ng h\u1ee3p l\u1ec7 do c\u00f3 tr\u01b0\u1eddng c\u00f3 gi\u00e1 tr\u1ecb ==null or undefined",
|
|
34
|
+
$mq$$.query);else{console.log("[joinData][manualQueries]",$mq$$.model.modelName,$mq$$.query);let $query$$=$mq$$.model.findOne($mq$$.query);$mq$$.fields&&($query$$=$query$$.select($mq$$.fields));$data$$=await $query$$.lean()}$data$$?($data$$._id&&($data$$._id=$data$$._id.toString()),$fetchedCache$$[$mq$$.cacheKey]=$data$$):$fetchedCache$$[$mq$$.cacheKey]=null}catch($e$$){console.error("\u274c[joinData][executeQueries] Manual Query Error:",$e$$),$fetchedCache$$[$mq$$.cacheKey]=null}finally{$pendingRequests$$.delete($key$$)}})();
|
|
35
|
+
$pendingRequests$$.set($key$$,$executionPromise$$);$promises$$.push($executionPromise$$)}});await Promise.all($promises$$)});return $fetchedCache$$}
|
|
35
36
|
async function mapResultsToItems($data$jscomp$2_items$$,$metaMap$$,$dataCache$$){for(let $item$$ of $data$jscomp$2_items$$){$data$jscomp$2_items$$=$metaMap$$.get($item$$)||[];for(let $meta$$ of $data$jscomp$2_items$$){const {join:$join$$,cacheKey:$cacheKey$$}=$meta$$;$data$jscomp$2_items$$=($data$jscomp$2_items$$=$dataCache$$[$cacheKey$$])||null;await applyFields($item$$,$data$jscomp$2_items$$||{},$join$$)}}}
|
|
36
37
|
async function applyFields($item$$,$data$$,$join$$){if($data$$)try{$join$$.fields&&(lodash.isFunction($join$$.fields)?$join$$.fields($item$$,$data$$):(Array.isArray($join$$.fields)?$join$$.fields:[$join$$.fields]).forEach($map$$=>{if(lodash.isObject($map$$))if($map$$.name&&$map$$.value)$item$$[$map$$.name]=$data$$[$map$$.value];else for(let $key_map$$ in $map$$)$item$$[$key_map$$]=$data$$[$map$$[$key_map$$]];else $item$$[$map$$]=$data$$[$map$$]})),$join$$.setFields&&$join$$.setFields($item$$,$data$$),
|
|
37
38
|
$join$$.asyncSetFields&&await $join$$.asyncSetFields($item$$,$data$$,()=>{}).catch(console.error)}catch($e$$){console.error("[joinData] [applyFields]",$e$$.message,JSON.stringify({item:$item$$,data:$data$$,join:$join$$},null,2))}}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const
|
|
2
|
-
error:{},status_string:{type:String},status_code:Number,provider:{type:String,default:"generic"},last_checked:{type:Date,default:null},status:{type:Boolean,default:!0},date_created:{type:Date,default:Date.now},date_updated:{type:Date,default:Date.now},user_created:{type:String,default:""},user_updated:{type:String,default:""}});
|
|
1
|
+
const imapSchema=new Schema({host:{type:String},port:{type:Number,default:993},secure:{type:Boolean,default:!0},mailbox:{type:String,default:"INBOX"},fetchsenders:{type:String,default:"invoice,hoadon"}},{_id:!1}),smtpSchema=new Schema({host:{type:String},port:{type:Number,default:465},ssl:{type:Boolean,default:!0}},{_id:!1}),mailaccountSchema=new Schema({id_app:{type:String,required:!0,maxlength:1024},id_link:{type:String},fullname:{type:String,required:!0},username:{type:String,required:!0},password:{type:String,
|
|
2
|
+
required:!0},imap:imapSchema,smtp:smtpSchema,error:{},status_string:{type:String},status_code:Number,provider:{type:String,default:"generic"},last_checked:{type:Date,default:null},status:{type:Boolean,default:!0},date_created:{type:Date,default:Date.now},date_updated:{type:Date,default:Date.now},user_created:{type:String,default:""},user_updated:{type:String,default:""}});
|
|
3
3
|
(global.configs||{}).createIndexes&&(mailaccountSchema.index({id_app:1,username:"text",fullname:"text"}),mailaccountSchema.index({id_app:1,username:1}),mailaccountSchema.index({id_app:1,fullname:1}),mailaccountSchema.index({id_app:1,id_link:1}),mailaccountSchema.index({id_app:1,status:1}),mailaccountSchema.index({id_app:1,user_created:1,visible_to:1,visible_to_users:1}));const model=mongoose.models.mailaccount||mongoose.model("mailaccount",mailaccountSchema);module.exports=model;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const productCodeSchema=new Schema({id_app:{type:String,required:!0,maxlength:1024},code:{type:String,required:!0},dmvt:{type:Schema.Types.ObjectId,ref:"dmvt",required:!0},is_scanned:{type:Boolean,default:!1},scan_count:{type:Number,default:0},scan_history:[{scanned_at:{type:Date,default:Date.now},ip:String,user_agent:String}],qr_image:String,status:{type:Boolean,default:!0},date_created:{type:Date,default:Date.now},date_updated:{type:Date,default:Date.now},user_created:{type:String,default:""},user_updated:{type:String,
|
|
2
|
+
default:""}});module.exports=mongoose.model("productcode",productCodeSchema);(global.configs||{}).createIndexes&&(productCodeSchema.index({id_app:1,code:1},{unique:!0}),productCodeSchema.index({id_app:1,dmvt:1}),productCodeSchema.index({id_app:1,dmvt:1,code:1}),productCodeSchema.index({id_app:1,user_created:1,visible_to:1,visible_to_users:1}));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const model=global.getModel("productcode"),controller=require("../../controllers/controller"),crypto=require("crypto"),qr=require("qr-image"),ejs=require("ejs"),path=require("path"),viewsDir=path.join(__dirname,"../../templates"),renderView=($data$$,$templateName$$="product-verify-result.ejs")=>new Promise(($resolve$$,$reject$$)=>{const $filePath$$=path.join(viewsDir,$templateName$$);ejs.renderFile($filePath$$,$data$$,($err$$,$str$$)=>{if($err$$)return $reject$$($err$$);$resolve$$($str$$)})});
|
|
2
|
+
module.exports=function($contr_router$$){$contr_router$$=new controller($contr_router$$,model,"productcode",{unique:["code"],notNeedRight:($user$$,$options$$={})=>($options$$.action||"").toLowerCase()=="view"?!0:!1,onView:async($user$$,$items$$,$next$$)=>{await $items$$.asyncJoinModel2($user$$.current_id_app,"dmvt",{where:{dmvt:"_id"},fields:["ma_vt","ten_vt","picture"]});$next$$(null,$items$$)}});$contr_router$$.createRoute("create-codes/:ma_vt/:quantity",async($req$$,$next$$)=>{try{var $createdCodes_ma_vt$$=
|
|
3
|
+
$req$$.params.ma_vt;const $quantity$$=Number($req$$.params.quantity||1),$product$$=await mongoose.model("dmvt").findOne({ma_vt:$createdCodes_ma_vt$$,id_app:$req$$.user.current_id_app}).lean();if(!$product$$)return $next$$({error:"S\u1ea3n ph\u1ea9m kh\u00f4ng t\u1ed3n t\u1ea1i"});$createdCodes_ma_vt$$=[];for(let $i$$=0;$i$$<($quantity$$||1);$i$$++){const $uniqueString$$=crypto.randomBytes(6).toString("hex"),$qrImage$$=`data:image/png;base64,${qr.imageSync(`${configs.api_url||configs.domain}/api/${$req$$.user.current_id_app}/productcode/verify/${$uniqueString$$}?access_token=${configs.public_token}`,
|
|
4
|
+
{type:"png",margin:2}).toString("base64")}`;await model.create({id_app:$req$$.user.current_id_app,code:$uniqueString$$,dmvt:$product$$._id,qr_image:$qrImage$$});$createdCodes_ma_vt$$.push({uniqueString:$uniqueString$$,qrImage:$qrImage$$})}$next$$(null,{success:!0,count:$createdCodes_ma_vt$$.length})}catch($error$$){$next$$({error:$error$$.message})}},{right_code:"add"});$contr_router$$.createRoute("verify/:code",async($req$$,$next$$)=>{const {code:$code$$}=$req$$.params,$clientIp$$=$req$$.headers["x-forwarded-for"]||
|
|
5
|
+
$req$$.socket.remoteAddress,$userAgent$$=$req$$.headers["user-agent"];try{const $codeInfo$$=await model.findOne({code:$code$$,id_app:$req$$.user.current_id_app}).populate("dmvt");let $renderData$$;$codeInfo$$?($codeInfo$$.scan_history.push({ip:$clientIp$$,user_agent:$userAgent$$}),$codeInfo$$.scan_count+=1,$codeInfo$$.is_scanned?(await $codeInfo$$.save(),$renderData$$={status:"WARNING",code:$code$$,company:$req$$.user.current_app_info||{},scanCount:$codeInfo$$.scan_count,product:$codeInfo$$.dmvt,
|
|
6
|
+
message:`C\u1ea3nh b\u00e1o: S\u1ea3n ph\u1ea9m n\u00e0y \u0111\u00e3 \u0111\u01b0\u1ee3c k\u00edch ho\u1ea1t tr\u01b0\u1edbc \u0111\u00f3 v\u00e0o ng\u00e0y ${$codeInfo$$.scan_history[0].scanned_at.toLocaleString()}. N\u1ebfu b\u1ea1n v\u1eeba m\u1edbi b\u00f3c tem, c\u00f3 th\u1ec3 \u0111\u00e2y l\u00e0 h\u00e0ng gi\u1ea3.`}):($codeInfo$$.is_scanned=!0,await $codeInfo$$.save(),$renderData$$={status:"GENUINE",code:$code$$,company:$req$$.user.current_app_info||{},product:$codeInfo$$.dmvt,scanCount:$codeInfo$$.scan_count,
|
|
7
|
+
message:"Ch\u00fac m\u1eebng! S\u1ea3n ph\u1ea9m ch\u00ednh h\u00e3ng v\u00e0 \u0111\u01b0\u1ee3c k\u00edch ho\u1ea1t l\u1ea7n \u0111\u1ea7u ti\u00ean."})):$renderData$$={status:"FAKE",code:$code$$,company:$req$$.user.current_app_info||{},scanCount:0,message:"M\u00e3 s\u1ea3n ph\u1ea9m kh\u00f4ng t\u1ed3n t\u1ea1i tr\u00ean h\u1ec7 th\u1ed1ng."};const $html$$=await renderView($renderData$$);$next$$(null,$html$$)}catch($error$$){console.error("[productcode]",$error$$),$next$$("System Error")}});$contr_router$$.route()};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Thông báo hợp đồng hết hạn bảo hành</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<h3>{{company.name}} thông báo hợp đồng sau đã hết hạn bảo hành</h3>
|
|
7
|
+
<p><b>Hợp đồng:</b> {{contract.ten_hd}}, số: {{contract.so_hd}}</p>
|
|
8
|
+
<p><b>Ngày ký:</b> {{contract.ngay_hd###}}</p>
|
|
9
|
+
<p><b>Khách hàng:</b> {{customer.ten_kh}}</p>
|
|
10
|
+
<p><b>Địa chỉ:</b> {{customer.dia_chi}}</p>
|
|
11
|
+
<p><b>Điện thoại:</b> {{customer.dien_thoai}}</p>
|
|
12
|
+
<p><b>Ngày bảo hành:</b> {{start_date###}}</p>
|
|
13
|
+
<p><b>Thời gian bảo hành:</b> {{warranty_time}} {{unit_time_name}}</p>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Thông báo hợp đồng hết hạn bảo hành</title>
|
|
4
|
+
</head>
|
|
5
|
+
body
|
|
6
|
+
h3=company.name+' thông báo hợp đồng sau đã hết hạn bảo hành'
|
|
7
|
+
p
|
|
8
|
+
b Hợp đồng:
|
|
9
|
+
!=contract.ten_hd+', số: ' + contract.so_hd
|
|
10
|
+
p
|
|
11
|
+
b Ngày ký:
|
|
12
|
+
!=moment(contract.ngay_hd).format("DD/MM/YYYY")
|
|
13
|
+
p
|
|
14
|
+
b Khách hàng:
|
|
15
|
+
!=customer.ten_kh
|
|
16
|
+
p
|
|
17
|
+
b Địa chỉ:
|
|
18
|
+
!=customer.dia_chi
|
|
19
|
+
p
|
|
20
|
+
b Điện thoại:
|
|
21
|
+
!=customer.dien_thoai
|
|
22
|
+
p
|
|
23
|
+
b Ngày bảo hành:
|
|
24
|
+
!=moment(start_date).format("DD/MM/YYYY")
|
|
25
|
+
p
|
|
26
|
+
b Thời gian bảo hành:
|
|
27
|
+
!=warranty_time.toString() + ' ' + unit_time_name
|
|
28
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Đơn đặt hàng</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<p>Đơn hàng được gửi tới từ <a href='{{app.site_name}}'>{{app.site_name}}</a>.</p>
|
|
7
|
+
<hr/>
|
|
8
|
+
<div>
|
|
9
|
+
<h1>ĐƠN ĐẶT HÀNG</h1>
|
|
10
|
+
<p>Số: <strong>{{order.so_ct}}</strong> - Ngày: <strong>{{order.ngay_ct}}</strong></p>
|
|
11
|
+
<p>Người nhận hàng: <strong>{{order.ten_nguoi_nhan}}</strong></p>
|
|
12
|
+
<p>Điện thoại: <strong>{{order.dien_thoai}}</strong></p>
|
|
13
|
+
<p>Email: <strong>{{order.email}}</strong></p>
|
|
14
|
+
<p>Địa chỉ: <strong>{{order.dia_chi}}, {{order.xa_phuong}}, {{order.quan_huyen}}, {{order.tinh_thanh}}</strong></p>
|
|
15
|
+
|
|
16
|
+
<p style='color:red'>Phương thức thanh toán: <strong>{{order.ten_pt_thanh_toan}}</strong></p>
|
|
17
|
+
<p>
|
|
18
|
+
<table style="border-collapse: collapse;border:1px solid gray;width:100%">
|
|
19
|
+
<tr>
|
|
20
|
+
<th style="border:1px solid gray;width:100px">Mã sản phẩm</th>
|
|
21
|
+
<th style="border:1px solid gray;width:250px">Tên sản phẩm</th>
|
|
22
|
+
<th style="border:1px solid gray;width:100px">Đơn vị tính</th>
|
|
23
|
+
<th style="border:1px solid gray;width:100px">Số lượng</th>
|
|
24
|
+
<th style="border:1px solid gray;width:100px">Giá</th>
|
|
25
|
+
<th style="border:1px solid gray;width:100px">Thành tiền</th>
|
|
26
|
+
</tr>
|
|
27
|
+
{{order.rows}}
|
|
28
|
+
<tr>
|
|
29
|
+
<td style="border:1px solid gray"></td>
|
|
30
|
+
<td style="border:1px solid gray"></td>
|
|
31
|
+
<td style="border:1px solid gray"><b>Tổng cộng</b></td>
|
|
32
|
+
<td style="border:1px solid gray"><b>{{order.t_sl}}</b></td>
|
|
33
|
+
<td style="border:1px solid gray"></td>
|
|
34
|
+
<td style="border:1px solid gray"><b>{{order.t_tt}}</b></td>
|
|
35
|
+
</tr>
|
|
36
|
+
</table>
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
</div>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Đơn đặt hàng</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
p='Đơn hàng được gửi tới từ '
|
|
7
|
+
a(href=app.site_name)=app.site_name
|
|
8
|
+
<hr/>
|
|
9
|
+
div
|
|
10
|
+
h1 ĐƠN ĐẶT HÀNG
|
|
11
|
+
p
|
|
12
|
+
!='Số: <strong>'+order.so_ct+'</strong> - Ngày: <strong>'+moment(order.ngay_ct).format('DD/MM/YYYY')+'</strong>'
|
|
13
|
+
p
|
|
14
|
+
!='Người nhận hàng: <strong>'+order.ten_nguoi_nhan+'</strong>'
|
|
15
|
+
p
|
|
16
|
+
!='Điện thoại: <strong>'+ order.dien_thoai+'</strong>'
|
|
17
|
+
p
|
|
18
|
+
!='Email: <strong>'+order.email+'</strong>'
|
|
19
|
+
p
|
|
20
|
+
!='Địa chỉ: <strong>' + order.dia_chi+', ' + order.xa_phuong + ', ' + order.quan_huyen + ', ' + order.tinh_thanh + '</strong>'
|
|
21
|
+
|
|
22
|
+
p(style='color:red')
|
|
23
|
+
!='Phương thức thanh toán: <strong>' + order.ten_pt_thanh_toan + '</strong>'
|
|
24
|
+
table(style="border-collapse: collapse;border:1px solid gray;width:100%")
|
|
25
|
+
tr
|
|
26
|
+
th(style="border:1px solid gray;width:100px") Mã sản phẩm
|
|
27
|
+
th(style="border:1px solid gray;width:250px") Tên sản phẩm
|
|
28
|
+
th(style="border:1px solid gray;width:100px") Đơn vị tính
|
|
29
|
+
th(style="border:1px solid gray;width:100px") Số lượng
|
|
30
|
+
th(style="border:1px solid gray;width:100px") Giá
|
|
31
|
+
th(style="border:1px solid gray;width:100px") Thành tiền
|
|
32
|
+
each row in order.details
|
|
33
|
+
tr
|
|
34
|
+
td(style='border:1px solid gray')=row.ma_vt
|
|
35
|
+
td(style='border:1px solid gray')=row.ten_vt
|
|
36
|
+
td(style='border:1px solid gray')=row.ma_dvt
|
|
37
|
+
td(style='border:1px solid gray')=numeral(row.sl_xuat).format("0,0.0")
|
|
38
|
+
td(style='border:1px solid gray')=numeral(row.gia_ban_thuc).format("0,0")
|
|
39
|
+
td(style='border:1px solid gray')=numeral(row.tien).format("0,0")
|
|
40
|
+
tr
|
|
41
|
+
td(style="border:1px solid gray")
|
|
42
|
+
td(style="border:1px solid gray")
|
|
43
|
+
td(style="border:1px solid gray")
|
|
44
|
+
b Tổng cộng
|
|
45
|
+
td(style="border:1px solid gray")
|
|
46
|
+
b=numeral(order.t_sl).format("0,0.0")
|
|
47
|
+
td(style="border:1px solid gray")
|
|
48
|
+
td(style="border:1px solid gray")
|
|
49
|
+
b=numeral(order.t_tt).format("0,0")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="vi">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
6
|
+
<title>Kết quả xác thực sản phẩm</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--color-success: #2ecc71;
|
|
10
|
+
--color-warning: #f39c12;
|
|
11
|
+
--color-danger: #e74c3c;
|
|
12
|
+
--color-text: #2c3e50;
|
|
13
|
+
--color-bg: #f4f6f8;
|
|
14
|
+
--font-main: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
font-family: var(--font-main);
|
|
21
|
+
background-color: var(--color-bg);
|
|
22
|
+
color: var(--color-text);
|
|
23
|
+
line-height: 1.6;
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
min-height: 100vh;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.container {
|
|
30
|
+
width: 100%;
|
|
31
|
+
max-width: 480px; /* Giới hạn chiều rộng như app mobile */
|
|
32
|
+
background: white;
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
box-shadow: 0 0 20px rgba(0,0,0,0.05);
|
|
36
|
+
position: relative;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* HEADER TRẠNG THÁI */
|
|
40
|
+
.status-header {
|
|
41
|
+
padding: 40px 20px;
|
|
42
|
+
text-align: center;
|
|
43
|
+
color: white;
|
|
44
|
+
border-bottom-left-radius: 30px;
|
|
45
|
+
border-bottom-right-radius: 30px;
|
|
46
|
+
margin-bottom: 20px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.status-icon {
|
|
50
|
+
font-size: 80px;
|
|
51
|
+
margin-bottom: 15px;
|
|
52
|
+
display: block;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.status-title {
|
|
56
|
+
font-size: 24px;
|
|
57
|
+
font-weight: 800;
|
|
58
|
+
text-transform: uppercase;
|
|
59
|
+
letter-spacing: 1px;
|
|
60
|
+
margin-bottom: 5px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.status-desc {
|
|
64
|
+
font-size: 16px;
|
|
65
|
+
opacity: 0.9;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* PRODUCT INFO */
|
|
69
|
+
.product-card {
|
|
70
|
+
padding: 0 25px;
|
|
71
|
+
text-align: center;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.product-image-wrapper {
|
|
75
|
+
width: 200px;
|
|
76
|
+
height: 200px;
|
|
77
|
+
margin: -60px auto 20px; /* Kéo ảnh lên đè lên header */
|
|
78
|
+
background: white;
|
|
79
|
+
border-radius: 20px;
|
|
80
|
+
padding: 10px;
|
|
81
|
+
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.product-image {
|
|
88
|
+
max-width: 100%;
|
|
89
|
+
max-height: 100%;
|
|
90
|
+
object-fit: contain;
|
|
91
|
+
border-radius: 10px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.product-name {
|
|
95
|
+
font-size: 20px;
|
|
96
|
+
font-weight: 700;
|
|
97
|
+
margin-bottom: 5px;
|
|
98
|
+
color: #333;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.product-code {
|
|
102
|
+
color: #7f8c8d;
|
|
103
|
+
font-size: 14px;
|
|
104
|
+
background: #eee;
|
|
105
|
+
padding: 4px 12px;
|
|
106
|
+
border-radius: 15px;
|
|
107
|
+
display: inline-block;
|
|
108
|
+
margin-bottom: 20px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* DETAILS BOX */
|
|
112
|
+
.detail-box {
|
|
113
|
+
margin: 20px;
|
|
114
|
+
padding: 20px;
|
|
115
|
+
background: #fff;
|
|
116
|
+
border: 1px solid #eee;
|
|
117
|
+
border-radius: 15px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.detail-row {
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: space-between;
|
|
123
|
+
margin-bottom: 12px;
|
|
124
|
+
padding-bottom: 12px;
|
|
125
|
+
border-bottom: 1px solid #f5f5f5;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.detail-row:last-child {
|
|
129
|
+
border-bottom: none;
|
|
130
|
+
margin-bottom: 0;
|
|
131
|
+
padding-bottom: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.label { color: #95a5a6; font-size: 14px; }
|
|
135
|
+
.value { font-weight: 600; font-size: 15px; text-align: right; }
|
|
136
|
+
|
|
137
|
+
/* BUTTON ACTION */
|
|
138
|
+
.action-area {
|
|
139
|
+
margin-top: auto;
|
|
140
|
+
padding: 20px;
|
|
141
|
+
text-align: center;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.btn {
|
|
145
|
+
display: block;
|
|
146
|
+
width: 100%;
|
|
147
|
+
padding: 15px;
|
|
148
|
+
border-radius: 12px;
|
|
149
|
+
text-decoration: none;
|
|
150
|
+
font-weight: bold;
|
|
151
|
+
font-size: 16px;
|
|
152
|
+
transition: opacity 0.2s;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.btn-support {
|
|
156
|
+
background-color: #f1f2f6;
|
|
157
|
+
color: #333;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* LOGIC MÀU SẮC */
|
|
161
|
+
/* Class động dựa trên biến status truyền vào */
|
|
162
|
+
.theme-GENUINE .status-header { background-color: var(--color-success); }
|
|
163
|
+
.theme-WARNING .status-header { background-color: var(--color-warning); }
|
|
164
|
+
.theme-FAKE .status-header { background-color: var(--color-danger); }
|
|
165
|
+
|
|
166
|
+
</style>
|
|
167
|
+
</head>
|
|
168
|
+
<body class="theme-<%= status %>">
|
|
169
|
+
|
|
170
|
+
<div class="container">
|
|
171
|
+
|
|
172
|
+
<div class="status-header">
|
|
173
|
+
<span class="status-icon">
|
|
174
|
+
<% if (status === 'GENUINE') { %>
|
|
175
|
+
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
|
|
176
|
+
<% } else if (status === 'WARNING') { %>
|
|
177
|
+
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
|
178
|
+
<% } else { %>
|
|
179
|
+
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>
|
|
180
|
+
<% } %>
|
|
181
|
+
</span>
|
|
182
|
+
|
|
183
|
+
<div class="status-title">
|
|
184
|
+
<% if (status === 'GENUINE') { %> CHÍNH HÃNG <% } %>
|
|
185
|
+
<% if (status === 'WARNING') { %> CẢNH BÁO <% } %>
|
|
186
|
+
<% if (status === 'FAKE') { %> KHÔNG RÕ NGUỒN GỐC <% } %>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="status-desc"><%= message %></div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<% if (status !== 'FAKE' && typeof product !== 'undefined') { %>
|
|
192
|
+
<div class="product-card">
|
|
193
|
+
<div class="product-image-wrapper">
|
|
194
|
+
<img src="<%= product.picture %>" alt="Product" class="product-image" onerror="this.src='https://via.placeholder.com/200?text=No+Image'">
|
|
195
|
+
</div>
|
|
196
|
+
<h2 class="product-name"><%= product.ten_vt %></h2>
|
|
197
|
+
<span class="product-code">Mã SP: <%= product.ma_vt %></span>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<div class="detail-box">
|
|
201
|
+
<% if (status === 'WARNING') { %>
|
|
202
|
+
<div class="detail-row" style="color: var(--color-danger)">
|
|
203
|
+
<span class="label" style="color: inherit">Số lần quét:</span>
|
|
204
|
+
<span class="value"><%= scanCount %> lần</span>
|
|
205
|
+
</div>
|
|
206
|
+
<% } %>
|
|
207
|
+
|
|
208
|
+
<div class="detail-row">
|
|
209
|
+
<span class="label">Ngày xác thực:</span>
|
|
210
|
+
<span class="value"><%= new Date().toLocaleDateString('vi-VN') %></span>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="detail-row">
|
|
213
|
+
<span class="label">Serial:</span>
|
|
214
|
+
<span class="value">...</span>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
<% } %>
|
|
218
|
+
|
|
219
|
+
<div class="action-area">
|
|
220
|
+
<% if (status === 'GENUINE') { %>
|
|
221
|
+
<a href="#" class="btn" style="background: var(--color-success); color: white;">Xem chi tiết sản phẩm</a>
|
|
222
|
+
<% } else { %>
|
|
223
|
+
<a href="tel:1900xxxx" class="btn btn-support">Liên hệ hỗ trợ: 1900 xxxx</a>
|
|
224
|
+
<% } %>
|
|
225
|
+
<p style="margin-top: 15px; font-size: 12px; color: #999;">Hệ thống xác thực chống hàng giả</p>
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
</div>
|
|
229
|
+
</body>
|
|
230
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>{{program}}</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<p>Xin chào {{receiver_name}},</p>
|
|
7
|
+
<p>Đây là thông tin mới dùng để đăng nhập vào tài khoản của bạn</p>
|
|
8
|
+
<p><b>Tên đăng nhập:</b>{{email}}</p>
|
|
9
|
+
<p><b>Mật khẩu:</b>{{password}}</p>
|
|
10
|
+
<p>Sau khi đăng nhập thành công, bạn nên đổi lại mật khẩu trên.</p>
|
|
11
|
+
<p>Nếu bạn không phải là người đã yêu cầu đổi mật khẩu thì bạn có thể bỏ qua email này, mật khẩu của bạn vẫn giữ nguyên.</p>
|
|
12
|
+
<p></p>
|
|
13
|
+
<p>Trân trọng,</p>
|
|
14
|
+
<p>{{company}}</p>
|
|
15
|
+
|
|
16
|
+
</body>
|
|
17
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
title=program
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
p='Xin chào '+receiver_name
|
|
7
|
+
p='Đây là thông tin mới dùng để đăng nhập vào tài khoản của bạn'
|
|
8
|
+
p
|
|
9
|
+
!='<b>Tên đăng nhập:</b>'+email
|
|
10
|
+
p
|
|
11
|
+
!='<b>Mật khẩu:</b>'+password
|
|
12
|
+
p Sau khi đăng nhập thành công, bạn nên đổi lại mật khẩu trên.
|
|
13
|
+
p Nếu bạn không phải là người đã yêu cầu đổi mật khẩu thì bạn có thể bỏ qua email này, mật khẩu của bạn vẫn giữ nguyên.
|
|
14
|
+
p
|
|
15
|
+
p Trân trọng,
|
|
16
|
+
p=company
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>{{program}}</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<p>Xin chào {{receiver_name}},</p>
|
|
7
|
+
<p>Đây là thông tin dùng để đăng nhập vào tài khoản của bạn trên chương trình <a href='{{domain}}'>{{domain}}</a></p>
|
|
8
|
+
<p><b>Tên đăng nhập:</b>{{email}}</p>
|
|
9
|
+
<p><b>Mật khẩu:</b>{{password}}</p>
|
|
10
|
+
<p>Sau khi đăng nhập thành công, bạn nên đổi lại mật khẩu trên.</p>
|
|
11
|
+
<p></p>
|
|
12
|
+
<p>Trân trọng,</p>
|
|
13
|
+
<p>{{company}}</p>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
title=program
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
p='Xin chào '+receiver_name+','
|
|
7
|
+
p='Đây là thông tin dùng để đăng nhập vào tài khoản của bạn trên chương trình '
|
|
8
|
+
a(href=domain)=domain
|
|
9
|
+
p
|
|
10
|
+
!='<b>Tên đăng nhập:</b>'+email
|
|
11
|
+
p
|
|
12
|
+
!='<b>Mật khẩu:</b>'+password
|
|
13
|
+
p Sau khi đăng nhập thành công, bạn nên đổi lại mật khẩu trên.
|
|
14
|
+
p
|
|
15
|
+
p Trân trọng,
|
|
16
|
+
p=company
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>{{program}}</title>
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
<div>Xin chào, {{receiver_name}}</div>
|
|
7
|
+
<p><b>{{sender_name}}</b> đã mời bạn tham gia nhóm làm việc tại <a href='{{domain}}'>{{domain}}</a></p>
|
|
8
|
+
<p>Để chấp nhận tham gia, bạn hãy đăng nhập vào chương trình tại <a href='{{domain}}'>{{domain}}</a></p>
|
|
9
|
+
<p></p>
|
|
10
|
+
<p>Trân trọng,</p>
|
|
11
|
+
<p>{{company}}</p>
|
|
12
|
+
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
title=program
|
|
4
|
+
</head>
|
|
5
|
+
<body>
|
|
6
|
+
div='Xin chào, ' + receiver_name
|
|
7
|
+
p
|
|
8
|
+
b=sender_name
|
|
9
|
+
|đã mời bạn tham gia nhóm làm việc tại
|
|
10
|
+
a(href=domain)=domain
|
|
11
|
+
p Để chấp nhận tham gia, bạn hãy đăng nhập vào chương trình tại
|
|
12
|
+
a(href=domain)=domain
|
|
13
|
+
p
|
|
14
|
+
p Trân trọng,
|
|
15
|
+
p=company
|
|
16
|
+
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|