Compare commits
20 Commits
03036fdffd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 51d8f0822f | |||
|
|
a2215b9363 | ||
|
|
20e4a15286 | ||
|
|
29ca0b9965 | ||
|
|
f54c5660ea | ||
|
|
a28576960e | ||
|
|
a661c06639 | ||
|
|
b9ed81beb7 | ||
|
|
06f834e8c9 | ||
|
|
945b479309 | ||
|
|
64479793ea | ||
|
|
706529f11d | ||
|
|
09b7f3b74b | ||
|
|
cb91e4dfcf | ||
|
|
61f5f8fe04 | ||
|
|
19d9d24530 | ||
|
|
e9d8383eaa | ||
|
|
f2d1234a6e | ||
|
|
9ac53000b4 | ||
|
|
2aeb3cb120 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
go.sum
|
||||||
|
go.work.sum
|
||||||
|
.idea
|
||||||
|
version.js
|
||||||
@@ -2,6 +2,9 @@ create domain dmn_code as text not null;
|
|||||||
create domain dmn_money as numeric(22, 4);
|
create domain dmn_money as numeric(22, 4);
|
||||||
create domain dmn_qty numeric(18, 6);
|
create domain dmn_qty numeric(18, 6);
|
||||||
create domain dmn_rate as numeric(5, 2);
|
create domain dmn_rate as numeric(5, 2);
|
||||||
|
create domain dmn_clid bigint not null check ( value > 0 );
|
||||||
|
create domain dmn_usrid bigint not null check ( value > 0 );
|
||||||
|
|
||||||
|
|
||||||
create function iif(condition boolean, true_result anyelement, false_result anyelement) returns anyelement
|
create function iif(condition boolean, true_result anyelement, false_result anyelement) returns anyelement
|
||||||
immutable
|
immutable
|
||||||
|
|||||||
26
db/migration/base/002.up.company.sql
Normal file
26
db/migration/base/002.up.company.sql
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
create table company (
|
||||||
|
clid dmn_clid,
|
||||||
|
id bigint generated by default as identity PRIMARY key,
|
||||||
|
code dmn_code,
|
||||||
|
title text,
|
||||||
|
is_active boolean default true not null,
|
||||||
|
|
||||||
|
notes text,
|
||||||
|
|
||||||
|
zlins_dttm timestamptz,
|
||||||
|
zlupd_dttm timestamptz,
|
||||||
|
|
||||||
|
constraint uq_company unique (clid, code)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TRIGGER zl_company before INSERT or UPDATE ON company
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION zllog();
|
||||||
|
|
||||||
|
create table company_usr (
|
||||||
|
id bigint generated by default as identity PRIMARY key,
|
||||||
|
company_id bigint not null,
|
||||||
|
usr_id dmn_usrid,
|
||||||
|
constraint uq_company_usr unique (company_id, usr_id),
|
||||||
|
constraint fk_company_usr_company foreign key (company_id)
|
||||||
|
references company(id) on update cascade on delete cascade
|
||||||
|
);
|
||||||
1
db/migration/base/003.up.company_tmpl.sql
Normal file
1
db/migration/base/003.up.company_tmpl.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
alter table company add tmpl jsonb;
|
||||||
12
db/migration/base/004.up.company to cm.sql
Normal file
12
db/migration/base/004.up.company to cm.sql
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
alter table company
|
||||||
|
rename to cm;
|
||||||
|
|
||||||
|
alter table cm
|
||||||
|
rename column title to name;
|
||||||
|
|
||||||
|
alter table company_usr
|
||||||
|
rename to cm_usr;
|
||||||
|
|
||||||
|
alter table cm_usr
|
||||||
|
rename column company_id to cm_id;
|
||||||
|
|
||||||
3
db/migration/base/005.up.cm_usr_cmid.sql
Normal file
3
db/migration/base/005.up.cm_usr_cmid.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
alter table cm_usr drop constraint uq_company_usr;
|
||||||
|
alter table cm_usr rename cm_id to cmid;
|
||||||
|
alter table cm_usr add constraint uq_cm_usr unique (cmid, usr_id);
|
||||||
59
db/sqls/cm.sql
Normal file
59
db/sqls/cm.sql
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
-- << Create
|
||||||
|
insert into cm ( clid
|
||||||
|
, code
|
||||||
|
, name
|
||||||
|
, is_active
|
||||||
|
, notes
|
||||||
|
, tmpl)
|
||||||
|
values ( @clid
|
||||||
|
, @code
|
||||||
|
, @name
|
||||||
|
, @is_active
|
||||||
|
, @notes
|
||||||
|
, @tmpl)
|
||||||
|
returning id
|
||||||
|
-- Create >>
|
||||||
|
|
||||||
|
-- << Read
|
||||||
|
select clid
|
||||||
|
, id
|
||||||
|
, code
|
||||||
|
, name
|
||||||
|
, is_active
|
||||||
|
, notes
|
||||||
|
, tmpl
|
||||||
|
|
||||||
|
from cm
|
||||||
|
where id = $1
|
||||||
|
-- Read >>
|
||||||
|
|
||||||
|
-- << Update
|
||||||
|
update cm
|
||||||
|
set code = @code
|
||||||
|
, name = @name
|
||||||
|
, is_active = @is_active
|
||||||
|
, notes = @notes
|
||||||
|
, tmpl = @tmpl
|
||||||
|
|
||||||
|
where id = @id
|
||||||
|
-- Update >>
|
||||||
|
|
||||||
|
-- << Delete
|
||||||
|
delete
|
||||||
|
from cm
|
||||||
|
where id = $1
|
||||||
|
-- Delete >>
|
||||||
|
|
||||||
|
-- << List
|
||||||
|
select clid
|
||||||
|
, id
|
||||||
|
, code
|
||||||
|
, name
|
||||||
|
, is_active
|
||||||
|
, notes
|
||||||
|
, tmpl
|
||||||
|
|
||||||
|
from cm {{.Where}}
|
||||||
|
{{.OrderBy}}
|
||||||
|
{{.Rows}}
|
||||||
|
-- List >>
|
||||||
Binary file not shown.
11
scripts/base_db_install.sh
Normal file
11
scripts/base_db_install.sh
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
apt update && apt upgrade
|
||||||
|
dpkg-reconfigure locales
|
||||||
|
dpkg-reconfigure tzdata
|
||||||
|
|
||||||
|
sudo apt install -y postgresql-common
|
||||||
|
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
|
||||||
|
apt -y install postgresql-16 mc rsync curl
|
||||||
|
|
||||||
|
cd /tmp && sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'tesnos.+ed';"
|
||||||
65
scripts/base_svc_install.sh
Normal file
65
scripts/base_svc_install.sh
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
APP=bordroesleme
|
||||||
|
|
||||||
|
apt update && apt upgrade
|
||||||
|
apt -y install mc rsync curl nginx
|
||||||
|
dpkg-reconfigure tzdata
|
||||||
|
|
||||||
|
useradd --system --shell=/usr/sbin/nologin ${APP}
|
||||||
|
|
||||||
|
mkdir -p /opt/${APP}/sqls
|
||||||
|
mkdir -p /opt/${APP}/migrate
|
||||||
|
mkdir -p /opt/${APP}/ui
|
||||||
|
mkdir -p /opt/${APP}/files
|
||||||
|
|
||||||
|
echo "Creating application service"
|
||||||
|
read -d '' sservice << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=${APP}
|
||||||
|
After=syslog.target
|
||||||
|
After=network.target
|
||||||
|
#Requires=postgresql.service
|
||||||
|
#Requires=memcached.service
|
||||||
|
#Requires=redis.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Modify these two values and uncomment them if you have
|
||||||
|
# repos with lots of files and get an HTTP error 500 because
|
||||||
|
# of that
|
||||||
|
###
|
||||||
|
LimitMEMLOCK=infinity
|
||||||
|
LimitNOFILE=1048576
|
||||||
|
|
||||||
|
RestartSec=2s
|
||||||
|
Type=simple
|
||||||
|
User=${APP}
|
||||||
|
Group=${APP}
|
||||||
|
WorkingDirectory=/opt/${APP}/
|
||||||
|
ExecStart=/opt/${APP}/${APP}
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
Environment=AUTHSERVER=http://127.0.0.1:40200 SQLSDIR=./sqls DBHOST=10.0.0.2 DBNAME=bordroesleme DBPASS=tesnos.+ed
|
||||||
|
|
||||||
|
# enable to bind to a port below 1024 uncomment
|
||||||
|
###
|
||||||
|
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
#AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
|
||||||
|
# Prevent writes to /usr, /boot, and /etc
|
||||||
|
ProtectSystem=full
|
||||||
|
|
||||||
|
# Prevent accessing /home, /root and /run/user
|
||||||
|
ProtectHome=true
|
||||||
|
|
||||||
|
# Execute pre and post scripts as root, otherwise it does it as User=
|
||||||
|
PermissionsStartOnly=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
echo "$sservice" > /etc/systemd/system/${APP}.service
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable ${APP}
|
||||||
|
|
||||||
55
scripts/publish.sh
Executable file
55
scripts/publish.sh
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
APP=bordroesleme
|
||||||
|
PRJ_ROOT=${HOME}/prj/notitek/bordro-esleme
|
||||||
|
SVC_ROOT=${PRJ_ROOT}/svc
|
||||||
|
UI_ROOT=${PRJ_ROOT}/ui
|
||||||
|
DEST_IP=37.27.82.185
|
||||||
|
|
||||||
|
echo "Building ${APP} executable"
|
||||||
|
cd ${SVC_ROOT}
|
||||||
|
if [[ $OSTYPE == 'darwin'* ]]; then
|
||||||
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o ./$APP ./main.go
|
||||||
|
else
|
||||||
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o ./$APP ./main.go
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building SPA"
|
||||||
|
cd ${UI_ROOT}
|
||||||
|
version="0.alfa"
|
||||||
|
dt=$(date +%y%m%d-%H%M)
|
||||||
|
# gt=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
echo "
|
||||||
|
const vdata = {
|
||||||
|
version: '${version}',
|
||||||
|
build: '$dt'
|
||||||
|
}
|
||||||
|
export default vdata" > ./version.js
|
||||||
|
quasar build
|
||||||
|
|
||||||
|
echo "Copying executables"
|
||||||
|
scp ${SVC_ROOT}/${APP} root@${DEST_IP}:/opt/${APP}/${APP}.new
|
||||||
|
# scp ${SVC_ROOT}/upgrader/upgrader root@${DEST_IP}:/opt/${APP}/upgrader
|
||||||
|
|
||||||
|
echo "Transferring additional files"
|
||||||
|
#rsync -azP ${SVC_ROOT}/templates/ root@${DEST_IP}:/opt/${APP}/templates --delete
|
||||||
|
rsync -azP ${PRJ_ROOT}/db/sqls root@${DEST_IP}:/opt/${APP} --delete
|
||||||
|
#rsync -azP ${SVC_ROOT}/fonts/ root@${DEST_IP}:/opt/${APP}/fonts --delete
|
||||||
|
rsync -azP ${PRJ_ROOT}/db/migration/base root@${DEST_IP}:/opt/${APP}/migrate --delete
|
||||||
|
rsync -azP ${UI_ROOT}/dist/spa/ root@${DEST_IP}:/opt/${APP}/ui --delete
|
||||||
|
|
||||||
|
echo "Migrating database"
|
||||||
|
ssh root@${DEST_IP} "/opt/migrater -folder /opt/${APP}/migrate/base -db ${APP} -host 10.0.0.2 -tracker base -migrate-table symigrate -password tesnos.+ed"
|
||||||
|
|
||||||
|
echo "Updating system"
|
||||||
|
ssh root@${DEST_IP} "sudo systemctl stop ${APP}.service"
|
||||||
|
ssh root@${DEST_IP} "sudo rm /opt/${APP}/${APP}"
|
||||||
|
ssh root@${DEST_IP} "sudo mv /opt/${APP}/${APP}.new /opt/${APP}/${APP}"
|
||||||
|
|
||||||
|
ssh root@${DEST_IP} "chown -R ${APP}.${APP} /opt/${APP}"
|
||||||
|
|
||||||
|
ssh root@${DEST_IP} "sudo systemctl start ${APP}.service"
|
||||||
|
|
||||||
|
# remove compiled binary
|
||||||
|
cd ${SVC_ROOT}
|
||||||
|
rm -rf ./$APP
|
||||||
162
svc/api/acompany.go
Normal file
162
svc/api/acompany.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bordro-esleme/model/company"
|
||||||
|
"git.makki.io/makki/libgo/cmn"
|
||||||
|
"git.makki.io/makki/libgo/dbu"
|
||||||
|
"git.makki.io/makki/libgo/mhttp"
|
||||||
|
"git.notitek.com.tr/common/notgo/nauth"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func companyGet(w http.ResponseWriter, r *http.Request) {
|
||||||
|
/*
|
||||||
|
tc := auth.TokenDataFromRequest(r)
|
||||||
|
rbac, err := tc.RBAC(r.Context(), auth.MdCompany)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !rbac.IsGrantedOp(auth.OpRead) && !tc.IsAdmin() {
|
||||||
|
mhttp.Forbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
id := cmn.StrToInt64(chi.URLParam(r, "id"))
|
||||||
|
data, err := company.DbRead(r.Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
if dbu.IsNoRowsErr(err) {
|
||||||
|
mhttp.NotFound(w)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func companyCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tc := nauth.TokenPayloadFromRequest(r)
|
||||||
|
/*
|
||||||
|
rbac, err := tc.RBAC(r.Context(), auth.MdCompany)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !rbac.IsGrantedOp(auth.OpCreate) && !tc.IsAdmin() {
|
||||||
|
mhttp.Forbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
data := company.New()
|
||||||
|
err := cmn.BodyToJsonReq(r, &data)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = data.DbCreate(r.Context(), tc.ClientID(), true, tc.UsrID())
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, data.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func companyUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tc := nauth.TokenPayloadFromRequest(r)
|
||||||
|
/*
|
||||||
|
rbac, err := tc.RBAC(r.Context(), auth.MdCompany)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !rbac.IsGrantedOp(auth.OpUpdate) && !tc.IsAdmin() {
|
||||||
|
mhttp.Forbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
data := company.New()
|
||||||
|
err := cmn.BodyToJsonReq(r, &data)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = data.DbUpdate(r.Context(), true, tc.UsrID())
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func companyDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tc := nauth.TokenPayloadFromRequest(r)
|
||||||
|
/*
|
||||||
|
rbac, err := tc.RBAC(r.Context(), auth.MdCompany)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !rbac.IsGrantedOp(auth.OpDelete) && !tc.IsAdmin() {
|
||||||
|
mhttp.Forbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
id := cmn.StrToInt64(chi.URLParam(r, "id"))
|
||||||
|
|
||||||
|
err := company.DbDelete(r.Context(), id, true, tc.UsrID())
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func companyList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
/*
|
||||||
|
tc := auth.TokenDataFromRequest(r)
|
||||||
|
rbac, err := tc.RBAC(r.Context(), auth.MdCompany)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !rbac.IsGrantedOp(auth.OpRead) && !tc.IsAdmin() {
|
||||||
|
mhttp.Forbidden(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
var data []company.Company
|
||||||
|
|
||||||
|
tr, err := dbu.NewTableRequestFromRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rp, err := dbu.NewRepoWithFile(r.Context(), "cm", nil)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
respData, err := rp.MList(tr, &data)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, respData)
|
||||||
|
}
|
||||||
44
svc/api/atmpl.go
Normal file
44
svc/api/atmpl.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"git.makki.io/makki/libgo/cmn"
|
||||||
|
"git.makki.io/makki/libgo/dbu"
|
||||||
|
"git.makki.io/makki/libgo/mhttp"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tmplPost(w http.ResponseWriter, r *http.Request) {
|
||||||
|
companyID := cmn.StrToInt64(chi.URLParam(r, "companyID"))
|
||||||
|
var body json.RawMessage
|
||||||
|
|
||||||
|
err := cmn.BodyToJsonReq(r, &body)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sq := "update cm set tmpl = $2 where id = $1"
|
||||||
|
_, err = dbu.DB.Exec(r.Context(), sq, companyID, body)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tmplGet(w http.ResponseWriter, r *http.Request) {
|
||||||
|
companyID := cmn.StrToInt64(chi.URLParam(r, "companyID"))
|
||||||
|
var body json.RawMessage
|
||||||
|
|
||||||
|
sq := "select tmpl from cm where id = $1"
|
||||||
|
err := dbu.DB.QueryRow(r.Context(), sq, companyID).Scan(&body)
|
||||||
|
if err != nil {
|
||||||
|
mhttp.InternalServerError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mhttp.ResponseSuccess(w, body)
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package public
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.makki.io/makki/libgo/mhttp"
|
|
||||||
"git.makki.io/makki/libgo/svc"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func login(w http.ResponseWriter, r *http.Request) {
|
|
||||||
authResp, err := svc.S.Authenticate(r)
|
|
||||||
if err != nil {
|
|
||||||
mhttp.InternalServerError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clientResp := authResp.GetEndUserReponse()
|
|
||||||
mhttp.ResponseSuccess(w, clientResp)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package public
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-chi/chi/v5"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Router() http.Handler {
|
|
||||||
r := chi.NewRouter()
|
|
||||||
|
|
||||||
// user authentication
|
|
||||||
r.Post("/login", login)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bordro-esleme/api/public"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.makki.io/makki/libgo/nauth"
|
"git.makki.io/makki/libgo/mhttp"
|
||||||
|
"git.notitek.com.tr/common/notgo/napi"
|
||||||
|
"git.notitek.com.tr/common/notgo/nauth"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -19,6 +20,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func HttpHandler(re enums.TRunEnv) http.Handler {
|
func HttpHandler(re enums.TRunEnv) http.Handler {
|
||||||
|
lookup := &mhttp.Lookup{
|
||||||
|
DoClientCheck: true,
|
||||||
|
Funcs: map[string]mhttp.LookupFunc{
|
||||||
|
"entegrator": napi.Entegrators,
|
||||||
|
|
||||||
|
"invmarket": napi.InvMarket,
|
||||||
|
|
||||||
|
"usr": napi.Usr,
|
||||||
|
"rates": napi.Currency,
|
||||||
|
},
|
||||||
|
CompanyCheckQueries: []string{"mmitem", "acchart", "ficomp"},
|
||||||
|
JwtAuth: svc.S.JWT,
|
||||||
|
}
|
||||||
|
|
||||||
mux := chi.NewRouter()
|
mux := chi.NewRouter()
|
||||||
|
|
||||||
// Gerekli middleware stack
|
// Gerekli middleware stack
|
||||||
@@ -50,17 +65,38 @@ func HttpHandler(re enums.TRunEnv) http.Handler {
|
|||||||
|
|
||||||
mux.Route("/api", func(mr chi.Router) {
|
mux.Route("/api", func(mr chi.Router) {
|
||||||
// Public Route endpoints
|
// Public Route endpoints
|
||||||
mr.Mount("/", public.Router())
|
mr.Post("/login", napi.Login)
|
||||||
//mr.Mount("/admin", admin.Router())
|
|
||||||
|
|
||||||
//protected end points
|
//protected end points
|
||||||
mr.Group(func(r chi.Router) {
|
mr.Group(func(r chi.Router) {
|
||||||
// Seek, verify and validate JWT tokens
|
// Seek, verify and validate JWT tokens
|
||||||
r.Use(jwtauth.Verifier(nauth.JWT))
|
r.Use(jwtauth.Verify(svc.S.JWT, jwtauth.TokenFromHeader, jwtauth.TokenFromCookie, jwtauth.TokenFromQuery))
|
||||||
|
|
||||||
// Handle valid / invalid tokens.
|
// Handle valid / invalid tokens.
|
||||||
r.Use(nauth.CheckTokenValidity)
|
r.Use(nauth.CheckTokenValidity)
|
||||||
|
|
||||||
|
// Set clientID
|
||||||
|
r.Use(nauth.ClientID)
|
||||||
|
|
||||||
|
// Handle valid / invalid tokens.
|
||||||
|
r.Use(nauth.CheckTokenValidity)
|
||||||
|
|
||||||
|
// lookup
|
||||||
|
r.Method("post", "/lookup/{query}", lookup)
|
||||||
|
|
||||||
|
// sy routes
|
||||||
|
r.Get("/sy/companies", napi.CompanyList)
|
||||||
|
|
||||||
|
// company routes
|
||||||
|
r.Get("/company/{id:[0-9]+}", companyGet)
|
||||||
|
r.Get("/company", companyList)
|
||||||
|
r.Put("/company", companyUpdate)
|
||||||
|
r.Post("/company", companyCreate)
|
||||||
|
r.Delete("/company/{id:[0-9]+}", companyDelete)
|
||||||
|
|
||||||
|
r.Post("/tmpl/{companyID:[0-9]+}", tmplPost)
|
||||||
|
r.Get("/tmpl/{companyID:[0-9]+}", tmplGet)
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module bordro-esleme
|
module bordro-esleme
|
||||||
|
|
||||||
go 1.22.1
|
go 1.22.2
|
||||||
|
|
||||||
toolchain go1.22.2
|
toolchain go1.22.2
|
||||||
|
|
||||||
@@ -9,5 +9,6 @@ require (
|
|||||||
git.notitek.com.tr/common/notgo v0.0.0-20240408194744-d12ce3096580 // indirect
|
git.notitek.com.tr/common/notgo v0.0.0-20240408194744-d12ce3096580 // indirect
|
||||||
github.com/go-chi/chi/v5 v5.0.12 // indirect
|
github.com/go-chi/chi/v5 v5.0.12 // indirect
|
||||||
github.com/go-chi/cors v1.2.1 // indirect
|
github.com/go-chi/cors v1.2.1 // indirect
|
||||||
|
github.com/guregu/null/v5 v5.0.0 // indirect
|
||||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"git.makki.io/makki/libgo/dbu"
|
"git.makki.io/makki/libgo/dbu"
|
||||||
"git.makki.io/makki/libgo/mlog"
|
"git.makki.io/makki/libgo/mlog"
|
||||||
"git.makki.io/makki/libgo/svc"
|
"git.makki.io/makki/libgo/svc"
|
||||||
|
"git.notitek.com.tr/common/notgo/nauth"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ func main() {
|
|||||||
if svc.S.DevMode() {
|
if svc.S.DevMode() {
|
||||||
expire = time.Hour * 48
|
expire = time.Hour * 48
|
||||||
}
|
}
|
||||||
err = s.SubscribeToAuthServer(expire)
|
err = nauth.SubscribeToAuthServer(s.Ctx, expire)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mlog.Fatal(err)
|
mlog.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
136
svc/model/company/company.go
Normal file
136
svc/model/company/company.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
package company
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.makki.io/makki/libgo/dbu"
|
||||||
|
"github.com/guregu/null/v5"
|
||||||
|
"log/slog"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Company struct {
|
||||||
|
ClID int64 `db:"clid" json:"-"`
|
||||||
|
ID int64 `db:"id"`
|
||||||
|
Code string `db:"code"`
|
||||||
|
Name null.String `db:"name"`
|
||||||
|
IsActive bool `db:"is_active"`
|
||||||
|
Notes null.String `db:"notes"`
|
||||||
|
|
||||||
|
Tmpl null.String `db:"tmpl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Company {
|
||||||
|
m := &Company{
|
||||||
|
IsActive: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// m.__DetailStruct__ = dbu.NewDetailData[*__DetailStruct__]("__sql_filename__", "__sql_masterlink_field__", "__struct_master_field_link__", true)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func DbRead(ctx context.Context, id int64) (*Company, error) {
|
||||||
|
rp, err := dbu.NewRepoWithFile(ctx, "cm", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data := New()
|
||||||
|
//rp.AddDetail(data.Auths)
|
||||||
|
err = rp.Read(id, data)
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Company) GetIDVal() int64 {
|
||||||
|
return m.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Company) SetMasterLinkVal(masterField string, val int64) {
|
||||||
|
reflect.ValueOf(m).Elem().FieldByName(masterField).SetInt(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DbDelete(ctx context.Context, id int64, log bool, usrID *int64) error {
|
||||||
|
tx, err := dbu.DB.Begin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback(ctx)
|
||||||
|
|
||||||
|
rp, err := dbu.NewRepoWithFile(ctx, "cm", tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if log {
|
||||||
|
var oldData *Company
|
||||||
|
oldData, err = DbRead(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return dbu.ParsedErrSuppressNoRows(err)
|
||||||
|
}
|
||||||
|
err = dbu.DB.LogDMLTx("d", "cm", oldData.ID, usrID, "", oldData, nil, tx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rp.Delete(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Company) DbCreate(ctx context.Context, clID int64, log bool, usrID *int64) error {
|
||||||
|
m.ClID = clID
|
||||||
|
|
||||||
|
rp, err := dbu.NewRepoWithFile(ctx, "cm", nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rp.Create(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if log {
|
||||||
|
err = dbu.DB.LogDMLTx("c", "cm", m.ID, usrID, "", nil, m, nil)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Company) DbUpdate(ctx context.Context, log bool, usrID *int64) error {
|
||||||
|
tx, err := dbu.DB.Begin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback(ctx)
|
||||||
|
|
||||||
|
rp, err := dbu.NewRepoWithFile(ctx, "cm", tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if log {
|
||||||
|
var oldData *Company
|
||||||
|
oldData, err = DbRead(ctx, m.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = dbu.DB.LogDMLTx("u", "cm", oldData.ID, usrID, "", oldData, m, tx)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rp.Update(m.ID, m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit(ctx)
|
||||||
|
}
|
||||||
@@ -13,13 +13,17 @@
|
|||||||
"build": "quasar build"
|
"build": "quasar build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@intlify/vite-plugin-vue-i18n": "^7.0.0",
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
"axios": "^1.2.1",
|
"axios": "^1.2.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"pinia": "^2.0.11",
|
"pinia": "^2.0.11",
|
||||||
"quasar": "^2.8.0",
|
"quasar": "^2.8.0",
|
||||||
|
"reconnecting-websocket": "^4.4.0",
|
||||||
"vue": "^3.4.18",
|
"vue": "^3.4.18",
|
||||||
"vue-router": "^4.0.12"
|
"vue-i18n": "^9.9.0",
|
||||||
|
"vue-router": "^4.0.12",
|
||||||
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@quasar/app-vite": "^1.8.0",
|
"@quasar/app-vite": "^1.8.0",
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
// Configuration for your app
|
// Configuration for your app
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
||||||
|
|
||||||
|
const { configure } = require('quasar/wrappers')
|
||||||
const { configure } = require('quasar/wrappers');
|
const path = require('path')
|
||||||
|
|
||||||
|
|
||||||
module.exports = configure(function (ctx) {
|
module.exports = configure(function (ctx) {
|
||||||
return {
|
return {
|
||||||
@@ -23,12 +22,14 @@ module.exports = configure(function (ctx) {
|
|||||||
boot: [
|
boot: [
|
||||||
'axios',
|
'axios',
|
||||||
'version',
|
'version',
|
||||||
|
'i18n',
|
||||||
'pinia',
|
'pinia',
|
||||||
|
'bus',
|
||||||
],
|
],
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||||
css: [
|
css: [
|
||||||
'app.scss'
|
'app.scss',
|
||||||
],
|
],
|
||||||
|
|
||||||
// https://github.com/quasarframework/quasar/tree/dev/extras
|
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||||
@@ -48,8 +49,8 @@ module.exports = configure(function (ctx) {
|
|||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
||||||
build: {
|
build: {
|
||||||
target: {
|
target: {
|
||||||
browser: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ],
|
browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
||||||
node: 'node20'
|
node: 'node20',
|
||||||
},
|
},
|
||||||
|
|
||||||
vueRouterMode: 'history', // available values: 'hash', 'history'
|
vueRouterMode: 'history', // available values: 'hash', 'history'
|
||||||
@@ -62,6 +63,8 @@ module.exports = configure(function (ctx) {
|
|||||||
// publicPath: '/',
|
// publicPath: '/',
|
||||||
// analyze: true,
|
// analyze: true,
|
||||||
env: {
|
env: {
|
||||||
|
showLangSelect: false,
|
||||||
|
wsActive: false,
|
||||||
apiAddr: (() => {
|
apiAddr: (() => {
|
||||||
if (process.env.CUSTOM_API) {
|
if (process.env.CUSTOM_API) {
|
||||||
return process.env.CUSTOM_API
|
return process.env.CUSTOM_API
|
||||||
@@ -98,19 +101,34 @@ module.exports = configure(function (ctx) {
|
|||||||
// viteVuePluginOptions: {},
|
// viteVuePluginOptions: {},
|
||||||
|
|
||||||
vitePlugins: [
|
vitePlugins: [
|
||||||
['vite-plugin-checker', {
|
[
|
||||||
|
'vite-plugin-checker', {
|
||||||
eslint: {
|
eslint: {
|
||||||
lintCommand: 'eslint "./**/*.{js,mjs,cjs,vue}"'
|
lintCommand: 'eslint "./**/*.{js,mjs,cjs,vue}"',
|
||||||
}
|
},
|
||||||
}, { server: false }]
|
}, { server: false },
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
'@intlify/vite-plugin-vue-i18n', {
|
||||||
|
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
|
||||||
|
// compositionOnly: false,
|
||||||
|
|
||||||
|
// if you want to use named tokens in your Vue I18n messages, such as 'Hello {name}',
|
||||||
|
// you need to set `runtimeOnly: false`
|
||||||
|
// runtimeOnly: false,
|
||||||
|
|
||||||
|
// you need to set i18n resource including paths !
|
||||||
|
include: path.resolve(__dirname, './src/i18n/**'),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
||||||
devServer: {
|
devServer: {
|
||||||
// https: true
|
// https: true
|
||||||
port:9400,
|
port: 9403,
|
||||||
open: true // opens browser window automatically
|
open: true, // opens browser window automatically
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
||||||
@@ -132,8 +150,10 @@ module.exports = configure(function (ctx) {
|
|||||||
'Notify',
|
'Notify',
|
||||||
'Loading',
|
'Loading',
|
||||||
'Dialog',
|
'Dialog',
|
||||||
'Meta'
|
'Meta',
|
||||||
]
|
'LocalStorage',
|
||||||
|
'SessionStorage'
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// animations: 'all', // --- includes all animations
|
// animations: 'all', // --- includes all animations
|
||||||
@@ -155,7 +175,7 @@ module.exports = configure(function (ctx) {
|
|||||||
// https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr
|
// https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr
|
||||||
ssr: {
|
ssr: {
|
||||||
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
||||||
// will mess up SSR
|
// will mess up SSR
|
||||||
|
|
||||||
// extendSSRWebserverConf (esbuildConf) {},
|
// extendSSRWebserverConf (esbuildConf) {},
|
||||||
// extendPackageJson (json) {},
|
// extendPackageJson (json) {},
|
||||||
@@ -169,8 +189,8 @@ module.exports = configure(function (ctx) {
|
|||||||
// (gets superseded if process.env.PORT is specified at runtime)
|
// (gets superseded if process.env.PORT is specified at runtime)
|
||||||
|
|
||||||
middlewares: [
|
middlewares: [
|
||||||
'render' // keep this as last one
|
'render', // keep this as last one
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
// https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
|
// https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
|
||||||
@@ -194,7 +214,7 @@ module.exports = configure(function (ctx) {
|
|||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor
|
||||||
capacitor: {
|
capacitor: {
|
||||||
hideSplashscreen: true
|
hideSplashscreen: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron
|
||||||
@@ -223,18 +243,18 @@ module.exports = configure(function (ctx) {
|
|||||||
builder: {
|
builder: {
|
||||||
// https://www.electron.build/configuration/configuration
|
// https://www.electron.build/configuration/configuration
|
||||||
|
|
||||||
appId: 'tr.com.notitek.bres'
|
appId: 'tr.com.notitek.bres',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
|
||||||
bex: {
|
bex: {
|
||||||
contentScripts: [
|
contentScripts: [
|
||||||
'my-content-script'
|
'my-content-script',
|
||||||
],
|
],
|
||||||
|
|
||||||
// extendBexScriptsConf (esbuildConf) {}
|
// extendBexScriptsConf (esbuildConf) {}
|
||||||
// extendBexManifestJson (json) {}
|
// extendBexManifestJson (json) {}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|||||||
16
ui/src/boot/bus.js
Normal file
16
ui/src/boot/bus.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// a Quasar CLI boot file (let's say /src/boot/bus.js)
|
||||||
|
|
||||||
|
import { EventBus } from 'quasar'
|
||||||
|
import { boot } from 'quasar/wrappers'
|
||||||
|
|
||||||
|
const bus = new EventBus()
|
||||||
|
|
||||||
|
export default boot(({ app }) => {
|
||||||
|
// for Options API
|
||||||
|
app.config.globalProperties.$bus = bus
|
||||||
|
|
||||||
|
// for Composition API
|
||||||
|
app.provide('bus', bus)
|
||||||
|
})
|
||||||
|
|
||||||
|
export { bus }
|
||||||
16
ui/src/boot/i18n.js
Normal file
16
ui/src/boot/i18n.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { boot } from 'quasar/wrappers'
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import messages from 'src/i18n'
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: 'tr',
|
||||||
|
globalInjection: true,
|
||||||
|
messages
|
||||||
|
})
|
||||||
|
|
||||||
|
export default boot(({ app }) => {
|
||||||
|
// Set i18n instance on app
|
||||||
|
app.use(i18n)
|
||||||
|
})
|
||||||
|
|
||||||
|
export { i18n }
|
||||||
9
ui/src/i18n/en.js
Normal file
9
ui/src/i18n/en.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import base from "src/libjs/i18n/en"
|
||||||
|
|
||||||
|
const prjI18n = {
|
||||||
|
menu: {
|
||||||
|
app: 'Applications'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {...base, ...prjI18n}
|
||||||
8
ui/src/i18n/index.js
Normal file
8
ui/src/i18n/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import enUS from './en'
|
||||||
|
import trTR from './tr'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
'tr': trTR,
|
||||||
|
'en-US': enUS,
|
||||||
|
'en-GB': enUS,
|
||||||
|
}
|
||||||
18
ui/src/i18n/tr.js
Normal file
18
ui/src/i18n/tr.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import base from "src/libjs/i18n/tr"
|
||||||
|
|
||||||
|
const prjI18n = {
|
||||||
|
menu: {
|
||||||
|
app: 'Uygulamalar'
|
||||||
|
},
|
||||||
|
Company: {
|
||||||
|
ID: 'Şirket ID',
|
||||||
|
Code: 'Şirket Kod',
|
||||||
|
Title: 'Şirket Ad',
|
||||||
|
IsActive: 'Kullanımda',
|
||||||
|
Notes: 'Açıklamalar',
|
||||||
|
Tmpl: 'Eşleme Şablonu'
|
||||||
|
},
|
||||||
|
Usr: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {...base, ...prjI18n}
|
||||||
@@ -1,26 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-layout view="lHh Lpr lFf" style="background-color: #f8fafc;">
|
<q-layout view="lHh Lpr lFf" style="background-color: #f8fafc;">
|
||||||
<q-header class="bg-white q-py-sm" bordered>
|
<q-drawer
|
||||||
<q-toolbar>
|
v-model="ld.leftDrawerOpen"
|
||||||
|
show-if-above
|
||||||
|
bordered
|
||||||
|
content-class="bg-grey-1"
|
||||||
|
>
|
||||||
|
<q-scroll-area class="fit">
|
||||||
|
<q-list>
|
||||||
|
<q-item-label header>
|
||||||
|
<q-img src="notitek.png" width="120px" class="q-mb-lg"/>
|
||||||
|
<br/>
|
||||||
|
Bordro Eşleme
|
||||||
|
<br/>
|
||||||
|
{{ $VERSION.version }}
|
||||||
|
<span style="font-size:0.7rem;">
|
||||||
|
{{ $VERSION.build }}
|
||||||
|
</span>
|
||||||
|
</q-item-label>
|
||||||
|
|
||||||
<q-toolbar-title>
|
<template v-for="m in ld.menu" :key="m.grantKey">
|
||||||
<q-img src="logo.png" width="120px" fit="contain"/>
|
<q-item :to="m.to" v-if="!m.children" active-class="text-pcolor1">
|
||||||
</q-toolbar-title>
|
<q-item-section avatar v-if="m.icon">
|
||||||
|
<q-icon :name="m.icon"/>
|
||||||
<q-btn
|
</q-item-section>
|
||||||
round
|
<q-item-section>
|
||||||
flat
|
<q-item-label>{{ m.label }}</q-item-label>
|
||||||
class="on-right"
|
</q-item-section>
|
||||||
icon="logout"
|
</q-item>
|
||||||
color="pcolor3"
|
<q-expansion-item
|
||||||
@click="logout"
|
v-else
|
||||||
/>
|
:icon="m.icon"
|
||||||
|
:label="m.label"
|
||||||
|
>
|
||||||
|
<q-item v-for="c in m.children" :key="c.grantKey" :to="c.to" exact :inset-level=".5" active-class="text-pcolor1">
|
||||||
|
<q-item-section avatar v-if="c.icon">
|
||||||
|
<q-icon :name="c.icon"/>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>{{ c.label }}</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-expansion-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
</q-list>
|
||||||
</q-toolbar>
|
</q-scroll-area>
|
||||||
</q-header>
|
</q-drawer>
|
||||||
|
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
@@ -29,11 +56,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { $VERSION } from 'boot/version'
|
||||||
|
import { inject, reactive } from 'vue'
|
||||||
import { useLoginStore } from 'stores/login'
|
import { useLoginStore } from 'stores/login'
|
||||||
|
import { menu } from 'src/lib/menu'
|
||||||
|
|
||||||
const loginStore = useLoginStore()
|
const loginStore = useLoginStore()
|
||||||
|
|
||||||
|
const ld = reactive({
|
||||||
|
leftDrawerOpen: true,
|
||||||
|
menu: menu(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const bus = inject('bus') // inside setup()
|
||||||
|
bus.on('toggleLeftDrawerOpen', () => {
|
||||||
|
ld.leftDrawerOpen = !ld.leftDrawerOpen
|
||||||
|
})
|
||||||
|
|
||||||
const logout = function () {
|
const logout = function () {
|
||||||
loginStore.logout()
|
loginStore.logout()
|
||||||
}
|
}
|
||||||
|
|||||||
140
ui/src/lib/menu.js
Normal file
140
ui/src/lib/menu.js
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import { useLoginStore } from 'stores/login'
|
||||||
|
const store = useLoginStore()
|
||||||
|
|
||||||
|
|
||||||
|
const tmenu = [
|
||||||
|
{
|
||||||
|
label: 'Şirket Tanımları',
|
||||||
|
icon: 'business',
|
||||||
|
grantKey: 'Company',
|
||||||
|
to: '/company'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Şablon Tasarımı',
|
||||||
|
icon: 'design_services',
|
||||||
|
grantKey: 'Tmpl',
|
||||||
|
to: '/tmpl'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Bordro Eşleme',
|
||||||
|
icon: 'summarize',
|
||||||
|
grantKey: 'Map',
|
||||||
|
to: '/map'
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
{
|
||||||
|
label:'Hesap Planı',
|
||||||
|
icon: 'mdi-database-edit',
|
||||||
|
grantKey: 'Data',
|
||||||
|
to: null,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'menu.fiCrn',
|
||||||
|
icon: 'mdi-server-network',
|
||||||
|
grantKey: 'fiCrn',
|
||||||
|
to: '/ficrn'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'menu.dfGeo',
|
||||||
|
icon: 'mdi-server-network',
|
||||||
|
grantKey: 'defGeo',
|
||||||
|
to: '/dfgeo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'menu.region',
|
||||||
|
icon: 'mdi-server-network',
|
||||||
|
grantKey: 'defGeo',
|
||||||
|
to: '/region'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'menu.translations',
|
||||||
|
icon: 'mdi-translate',
|
||||||
|
grantKey: 'Locale',
|
||||||
|
to: '/locale'
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'menu.systemManagement',
|
||||||
|
icon: 'build_circle',
|
||||||
|
grantKey: 'System',
|
||||||
|
to: null,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: 'menu.syusr',
|
||||||
|
icon: 'mdi-badge-account-horizontal',
|
||||||
|
grantKey: 'syUsr',
|
||||||
|
to: '/syusr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'menu.syunit',
|
||||||
|
icon: 'mdi-account-group',
|
||||||
|
grantKey: 'syUnit',
|
||||||
|
to: '/syunit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'menu.systemParams',
|
||||||
|
icon: 'settings_applications',
|
||||||
|
grantKey: 'syParams',
|
||||||
|
to: '/syparams'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Log Auth',
|
||||||
|
icon: 'receipt',
|
||||||
|
grantKey: 'LogAuth',
|
||||||
|
to: '/logauth'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Log DML',
|
||||||
|
icon: 'receipt',
|
||||||
|
grantKey: 'LogDML',
|
||||||
|
to: '/logdml'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
*/
|
||||||
|
]
|
||||||
|
|
||||||
|
export const menu = function () {
|
||||||
|
const m = tmenu.filter(m => {
|
||||||
|
return checkGrant(m.grantKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const checkGrant = function (typ) {
|
||||||
|
//todo:
|
||||||
|
return true
|
||||||
|
|
||||||
|
if (store.IsAdmin) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store.grantHasKey(typ)) {
|
||||||
|
const o = store.Grants[typ]
|
||||||
|
for (let [key, value] of Object.entries(o)) {
|
||||||
|
if (value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkRprGrant = function (typ) {
|
||||||
|
if (this.$store.IsAdmin) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.Grants.Rpr[typ]
|
||||||
|
}
|
||||||
101
ui/src/model/company.js
Normal file
101
ui/src/model/company.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import { Model } from 'src/libjs/lib/model'
|
||||||
|
import { i18n } from 'boot/i18n'
|
||||||
|
const t = i18n.global.t
|
||||||
|
|
||||||
|
class Company extends Model {
|
||||||
|
ID = null
|
||||||
|
Code = ''
|
||||||
|
Name = ''
|
||||||
|
IsActive = true
|
||||||
|
Notes = ''
|
||||||
|
|
||||||
|
Tmpl = ''
|
||||||
|
|
||||||
|
_colOptions = {
|
||||||
|
ID: {
|
||||||
|
label: t('Company.ID'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
Code: {
|
||||||
|
label: t('Company.Code'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
Name: {
|
||||||
|
label: t('Company.Title'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
IsActive: {
|
||||||
|
label: t('Company.IsActive'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
Notes: {
|
||||||
|
label: t('Company.Notes'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
Tmpl: {
|
||||||
|
label: t('Company.Tmpl'),
|
||||||
|
visible: true,
|
||||||
|
dataType: 'text', //numeric, text, date, bool, datetime, time, inet
|
||||||
|
sortable: true,
|
||||||
|
showFilter: true,
|
||||||
|
|
||||||
|
//filterOptions: {},
|
||||||
|
//render: (val, row) => {}
|
||||||
|
//alias: '' //--> backend için, joinli tablolarda alias kullanımı. tableRequest'te fixFieldName cehennemine son vermek için
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (endPoint) {
|
||||||
|
super(endPoint)
|
||||||
|
this._ignoredFieldsOnPost = ['GrpCode', 'ClsCode', 'SpeCode']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Company
|
||||||
112
ui/src/pages/company.vue
Normal file
112
ui/src/pages/company.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<template>
|
||||||
|
<q-page padding>
|
||||||
|
<m-edit-header
|
||||||
|
title="Şirket Kaydı"
|
||||||
|
:id="model.ID"
|
||||||
|
:show-save-cancel="true"
|
||||||
|
@save="save"
|
||||||
|
@cancel="cancel"
|
||||||
|
/>
|
||||||
|
<q-form ref="frmMain" greedy autofocus>
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="row q-col-gutter-md">
|
||||||
|
|
||||||
|
|
||||||
|
<q-input class="col-xs-12 col-sm-4"
|
||||||
|
v-model="model.Code"
|
||||||
|
:label="t('Company.Code')"
|
||||||
|
bottom-slots
|
||||||
|
:rules="[rules.required]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-input class="col-xs-12 col-sm-6"
|
||||||
|
v-model="model.Name"
|
||||||
|
:label="t('Company.Title')"
|
||||||
|
bottom-slots
|
||||||
|
:rules="[]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-checkbox class="col-xs-12 col-sm-2"
|
||||||
|
v-model="model.IsActive"
|
||||||
|
:label="model._colOptions.IsActive.label"
|
||||||
|
bottom-slots
|
||||||
|
:rules="[]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row q-col-gutter-md">
|
||||||
|
<q-input class="col"
|
||||||
|
v-model="model.Notes"
|
||||||
|
:label="t('Company.Notes')"
|
||||||
|
bottom-slots
|
||||||
|
:rules="[]"
|
||||||
|
autogrow
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
|
||||||
|
</q-form>
|
||||||
|
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import MEditHeader from 'src/libjs/comp/MEditHeader.vue'
|
||||||
|
import { onBeforeMount, reactive, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { useLoginStore } from 'stores/login'
|
||||||
|
import Company from 'src/model/company'
|
||||||
|
import { rules } from 'src/libjs/lib/validation'
|
||||||
|
import { i18n } from 'boot/i18n'
|
||||||
|
|
||||||
|
const t = i18n.global.t
|
||||||
|
|
||||||
|
const frmMain = ref(null)
|
||||||
|
|
||||||
|
const endPoint = ref('/company')
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const store = useLoginStore()
|
||||||
|
const model = reactive(new Company(endPoint.value))
|
||||||
|
|
||||||
|
const ld = reactive({})
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
if (route.params.id) {
|
||||||
|
load()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const load = function () {
|
||||||
|
const id = route.params.id
|
||||||
|
if (!id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
model.read(id).then(() => {
|
||||||
|
// do some other stuff
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = function () {
|
||||||
|
frmMain.value.validate().then(success => {
|
||||||
|
if (success) {
|
||||||
|
model.save(false)
|
||||||
|
} else {
|
||||||
|
// oh no, user has filled in
|
||||||
|
// at least one invalid value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancel = function () {
|
||||||
|
router.push(endPoint.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
30
ui/src/pages/companyList.vue
Normal file
30
ui/src/pages/companyList.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<q-page padding>
|
||||||
|
<m-edit-header title="Şirket Tanımları"/>
|
||||||
|
<m-list
|
||||||
|
:url="ld.endPoint"
|
||||||
|
:model="model"
|
||||||
|
>
|
||||||
|
</m-list>
|
||||||
|
</q-page>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Company from 'src/model/company'
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
import useLoginStore from 'stores/login'
|
||||||
|
import MEditHeader from 'src/libjs/comp/MEditHeader.vue'
|
||||||
|
import MList from 'src/libjs/comp/MList.vue'
|
||||||
|
|
||||||
|
const $q = useQuasar()
|
||||||
|
|
||||||
|
const store = useLoginStore()
|
||||||
|
|
||||||
|
const ld = reactive({
|
||||||
|
endPoint: '/company'
|
||||||
|
})
|
||||||
|
|
||||||
|
const model = ref(new Company(ld.endPoint))
|
||||||
|
</script>
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="flex flex-center">
|
<q-page padding>
|
||||||
<img
|
<m-edit-header
|
||||||
alt="Quasar logo"
|
show-company-select
|
||||||
src="~assets/quasar-logo-vertical.svg"
|
:show-lang-selector="false"
|
||||||
style="width: 200px; height: 200px"
|
/>
|
||||||
>
|
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import MEditHeader from 'src/libjs/comp/MEditHeader.vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'IndexPage'
|
name: 'IndexPage'
|
||||||
});
|
});
|
||||||
|
|||||||
356
ui/src/pages/map.vue
Normal file
356
ui/src/pages/map.vue
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
<template>
|
||||||
|
<q-page padding>
|
||||||
|
<m-edit-header title="Bordro Eşleme"/>
|
||||||
|
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<q-select v-model="ld.companyID"
|
||||||
|
map-options
|
||||||
|
emit-value
|
||||||
|
:label="t('selectCompany')"
|
||||||
|
:options="ld.companies"
|
||||||
|
option-value="ID"
|
||||||
|
option-label="Name"
|
||||||
|
dense
|
||||||
|
options-dense
|
||||||
|
outlined
|
||||||
|
bg-color="white"
|
||||||
|
@update:model-value="load"
|
||||||
|
>
|
||||||
|
<template v-slot:after>
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
icon="business"
|
||||||
|
dense
|
||||||
|
size="sm"
|
||||||
|
color="white"
|
||||||
|
to="/company/new"
|
||||||
|
>
|
||||||
|
<q-tooltip>{{ t('createCompany') }}</q-tooltip>
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section v-if="ld.companyID && ld.canProcess">
|
||||||
|
<div class="row q-gutter-y-sm q-col-gutter-md">
|
||||||
|
<q-file
|
||||||
|
dense
|
||||||
|
class="col"
|
||||||
|
v-model="ld.xlsFileName"
|
||||||
|
label="Bordro Dosyası"
|
||||||
|
clearable
|
||||||
|
@update:modelValue="loadFile"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<q-select
|
||||||
|
class="col"
|
||||||
|
v-model="ld.bordroSheet"
|
||||||
|
:options="ld.sheets"
|
||||||
|
label="Bordro Sayfası"
|
||||||
|
dense
|
||||||
|
:disable="!ld.xlsFileName"
|
||||||
|
>
|
||||||
|
<template v-slot:after>
|
||||||
|
<q-btn
|
||||||
|
outline
|
||||||
|
color="pcolor1"
|
||||||
|
label="Bordro Fişi Oluştur"
|
||||||
|
no-caps
|
||||||
|
@click="doProcess"
|
||||||
|
:disable="!ld.bordroSheet"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, reactive } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { api } from 'boot/axios'
|
||||||
|
import { catchAxiosError, showAxiosError } from 'src/libjs/lib/axios'
|
||||||
|
import MEditHeader from 'src/libjs/comp/MEditHeader.vue'
|
||||||
|
import { read, utils, writeFile } from 'xlsx'
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const $q = useQuasar()
|
||||||
|
|
||||||
|
const ld = reactive({
|
||||||
|
companyID: null,
|
||||||
|
companies: [],
|
||||||
|
|
||||||
|
sheets: [],
|
||||||
|
bordroSheet: '',
|
||||||
|
|
||||||
|
xlsFileName: null,
|
||||||
|
selectedVal: '',
|
||||||
|
alreadySelectedValFields: {},
|
||||||
|
|
||||||
|
canProcess: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
const tmpl = reactive({
|
||||||
|
rawData: null,
|
||||||
|
sheets: [],
|
||||||
|
bordroSheet: '',
|
||||||
|
|
||||||
|
baslikSatiri: 7,
|
||||||
|
baslikSatirAdedi: 2,
|
||||||
|
|
||||||
|
kontrolKolonu: -1,
|
||||||
|
|
||||||
|
alanlar: [],
|
||||||
|
kriterler: {},
|
||||||
|
dagitim: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getCompanyList()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getCompanyList = function () {
|
||||||
|
api.get('/sy/companies').then(res => {
|
||||||
|
if (res.data.Success) {
|
||||||
|
ld.companies = res.data.Data || []
|
||||||
|
} else {
|
||||||
|
showAxiosError(res)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
catchAxiosError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const load = function () {
|
||||||
|
Object.keys(ld.alreadySelectedValFields).forEach(k => {
|
||||||
|
delete ld.alreadySelectedValFields[k]
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.keys(tmpl.kriterler).forEach(k => {
|
||||||
|
delete tmpl.kriterler[k]
|
||||||
|
})
|
||||||
|
tmpl.sheets.splice(0)
|
||||||
|
tmpl.alanlar.splice(0)
|
||||||
|
tmpl.bordroSheet = ''
|
||||||
|
|
||||||
|
$q.loading.show()
|
||||||
|
api.get(`/tmpl/${ld.companyID}`).then(res => {
|
||||||
|
if (res.data.Success) {
|
||||||
|
if (res.data.Data === null) {
|
||||||
|
ld.canProcess = false
|
||||||
|
$q.dialog({
|
||||||
|
title: 'Hata',
|
||||||
|
message: 'Şirket için tanımlı şablon yok',
|
||||||
|
}).onOk(() => {
|
||||||
|
// console.log('OK')
|
||||||
|
}).onCancel(() => {
|
||||||
|
// console.log('Cancel')
|
||||||
|
}).onDismiss(() => {
|
||||||
|
// console.log('I am triggered on both OK and Cancel')
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ld.canProcess = true
|
||||||
|
|
||||||
|
Object.keys(res.data.Data).forEach(k => {
|
||||||
|
tmpl[k] = res.data.Data[k]
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (k !== 'alanlar') {
|
||||||
|
tmpl[k] = res.data.Data[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
//tmpl.rawData = new Uint8Array(res.data.Data.rawData)
|
||||||
|
//workbook = read(tmpl.rawData)
|
||||||
|
|
||||||
|
Object.keys(tmpl.kriterler).forEach(k => {
|
||||||
|
tmpl.kriterler[k].valFields.forEach(f => {
|
||||||
|
ld.alreadySelectedValFields[f] = 'x'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
showAxiosError()
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
catchAxiosError(err)
|
||||||
|
}).finally(() => {
|
||||||
|
$q.loading.hide()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let workbook = null
|
||||||
|
|
||||||
|
const loadFile = function () {
|
||||||
|
const reader = new FileReader()
|
||||||
|
/*
|
||||||
|
reader.addEventListener('load', (event) => {
|
||||||
|
console.log(event.target.result)
|
||||||
|
});
|
||||||
|
reader.readAsDataURL(ld.xlsFile);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
reader.onload = function (e) {
|
||||||
|
const uin = new Uint8Array(e.target.result)
|
||||||
|
|
||||||
|
ld.sheets.splice(0)
|
||||||
|
workbook = read(uin)
|
||||||
|
ld.sheets.push(...workbook.SheetNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$q.loading.show()
|
||||||
|
reader.readAsArrayBuffer(ld.xlsFileName)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
$q.loading.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doProcess = function () {
|
||||||
|
try {
|
||||||
|
$q.loading.show()
|
||||||
|
processXLS()
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
} finally {
|
||||||
|
$q.loading.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hesapKodBul = function (row, fieldName) {
|
||||||
|
// Hesap kodunu bulalım
|
||||||
|
let hesapKod = ''
|
||||||
|
Object.keys(tmpl.kriterler).forEach(k => {
|
||||||
|
const kriter = tmpl.kriterler[k]
|
||||||
|
|
||||||
|
let kriterVal = ''
|
||||||
|
|
||||||
|
if (kriter.colNro >= 0) {
|
||||||
|
// sabit kriter alanı
|
||||||
|
kriterVal = row[kriter.colNro]
|
||||||
|
} else {
|
||||||
|
const tmpValues = []
|
||||||
|
tmpl.kriterler[k].combinedFieldsNro.forEach(cf => {
|
||||||
|
let tmpKriterVal = row[cf]
|
||||||
|
if ((tmpKriterVal === null) || (tmpKriterVal === undefined)) {
|
||||||
|
tmpKriterVal = ''
|
||||||
|
}
|
||||||
|
tmpValues.push(tmpKriterVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
kriterVal = tmpValues.join(' ').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = kriter.mappings[kriterVal]
|
||||||
|
|
||||||
|
if ((map !== undefined) && (map !== null)) {
|
||||||
|
const tmpHesapKod = map[fieldName]
|
||||||
|
if (tmpHesapKod) {
|
||||||
|
hesapKod = tmpHesapKod
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(kriter)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return hesapKod
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const processXLS = function () {
|
||||||
|
const sheet = workbook.Sheets[ld.bordroSheet]
|
||||||
|
const rawData = utils.sheet_to_json(sheet, { header: 1 })
|
||||||
|
|
||||||
|
const bordro = []
|
||||||
|
|
||||||
|
const dagitimKeys = Object.keys(tmpl.dagitim)
|
||||||
|
|
||||||
|
rawData.forEach((row, ndx) => {
|
||||||
|
if (ndx <= tmpl.baslikSatiri - 1 + tmpl.baslikSatirAdedi) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const kval = row[tmpl.kontrolKolonu]
|
||||||
|
if ((kval !== null) && (kval !== undefined) && (kval !== '')) {
|
||||||
|
|
||||||
|
const bordroRow = {}
|
||||||
|
|
||||||
|
// sabit alanları verelim
|
||||||
|
tmpl.alanlar.filter(a => {return a.showInSlip}).forEach(a => {
|
||||||
|
if (a.colNro >= 0) {
|
||||||
|
bordroRow[a.fieldName] = row[a.colNro]
|
||||||
|
} else {
|
||||||
|
const tmpValues = []
|
||||||
|
a.combinedFieldsNro.forEach(cf => {
|
||||||
|
let tmpVal = row[cf]
|
||||||
|
if ((tmpVal === null) || (tmpVal === undefined)) {
|
||||||
|
tmpVal = ''
|
||||||
|
}
|
||||||
|
tmpValues.push(tmpVal)
|
||||||
|
})
|
||||||
|
|
||||||
|
bordroRow[a.fieldName] = tmpValues.join(' ').trim()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// veri alanlarını verelim
|
||||||
|
tmpl.alanlar.filter(a => {return a.colType === 'veri'}).forEach(veri => {
|
||||||
|
|
||||||
|
let dagitimYapildi = false
|
||||||
|
if (dagitimKeys.length > 0) {
|
||||||
|
dagitimKeys.forEach(bazAlan => {
|
||||||
|
const degerler = Object.keys(tmpl.dagitim[bazAlan].kural)
|
||||||
|
degerler.forEach(deger => {
|
||||||
|
if (deger === row[tmpl.dagitim[bazAlan].bazAlanColNro]) {
|
||||||
|
dagitimYapildi = true
|
||||||
|
tmpl.dagitim[bazAlan].kural[deger].forEach(oran => {
|
||||||
|
//row'ın bir kopyasını oluşturalım çünkü hesap kodunu bu yeni row'a göre bulacağız
|
||||||
|
const tmpRow = [...row]
|
||||||
|
tmpRow[tmpl.dagitim[bazAlan].hedefAlanColNro] = oran.deger
|
||||||
|
bordroRow['Hesap'] = hesapKodBul(tmpRow, veri.fieldName)
|
||||||
|
bordroRow['Masraf Açıklama'] = veri.fieldName
|
||||||
|
bordroRow['Tutar'] = row[veri.colNro] * (oran.oran / 100)
|
||||||
|
bordroRow['B/A'] = veri.ba
|
||||||
|
|
||||||
|
const hedefAlan = tmpl.dagitim[bazAlan].hedefAlan
|
||||||
|
if (bordroRow[hedefAlan]) {
|
||||||
|
bordroRow[hedefAlan] = oran.deger
|
||||||
|
}
|
||||||
|
|
||||||
|
bordro.push({ ...bordroRow })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dagitimYapildi) {
|
||||||
|
bordroRow['Hesap'] = hesapKodBul(row, veri.fieldName)
|
||||||
|
bordroRow['Masraf Açıklama'] = veri.fieldName
|
||||||
|
bordroRow['Tutar'] = row[veri.colNro]
|
||||||
|
bordroRow['B/A'] = veri.ba
|
||||||
|
|
||||||
|
bordro.push({ ...bordroRow })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const newSheet = utils.json_to_sheet(bordro)
|
||||||
|
const newWB = utils.book_new()
|
||||||
|
utils.book_append_sheet(newWB, newSheet, 'veri')
|
||||||
|
writeFile(newWB, 'bordro.xlsx', { compression: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
1056
ui/src/pages/tmpl.vue
Normal file
1056
ui/src/pages/tmpl.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -41,8 +41,7 @@ Router.beforeEach(
|
|||||||
// instead of having to check every route record with
|
// instead of having to check every route record with
|
||||||
// to.matched.some(record => record.meta.requiresAuth)
|
// to.matched.some(record => record.meta.requiresAuth)
|
||||||
|
|
||||||
if (to.meta.requiresAuth && !isLoggedIn &&
|
if (to.meta.requiresAuth && !isLoggedIn && to.path !== 'login') {
|
||||||
((to.path !== '/') || (to.path !== 'login'))) {
|
|
||||||
// this route requires auth, check if logged in
|
// this route requires auth, check if logged in
|
||||||
// if not, redirect to login page.
|
// if not, redirect to login page.
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ Router.beforeEach(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isLoggedIn) && ((to.path === '/') || (to.path === 'login'))) {
|
if (isLoggedIn && to.path === 'login') {
|
||||||
return {
|
return {
|
||||||
path: '/',
|
path: '/',
|
||||||
query: '',
|
query: '',
|
||||||
|
|||||||
@@ -9,6 +9,16 @@ const routes = [
|
|||||||
children: [
|
children: [
|
||||||
{ path: '', component: () => import('pages/index.vue') },
|
{ path: '', component: () => import('pages/index.vue') },
|
||||||
{ path: '/panel', component: () => import('pages/index.vue') },
|
{ path: '/panel', component: () => import('pages/index.vue') },
|
||||||
|
|
||||||
|
{ path: '/company', component: () => import('pages/companyList.vue') },
|
||||||
|
{ path: '/company/edit/:id', component: () => import('pages/company.vue') },
|
||||||
|
{ path: '/company/new', component: () => import('pages/company.vue') },
|
||||||
|
// { path: '/company/:id', component: () => import('pages/companyView.vue') },
|
||||||
|
|
||||||
|
{ path: '/tmpl', component: () => import('pages/tmpl.vue') },
|
||||||
|
{ path: '/map', component: () => import('pages/map.vue') },
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,34 @@ import { LocalStorage } from 'quasar'
|
|||||||
import { api } from 'boot/axios'
|
import { api } from 'boot/axios'
|
||||||
import { jwtDecode } from "jwt-decode"
|
import { jwtDecode } from "jwt-decode"
|
||||||
import Router from 'src/router/index'
|
import Router from 'src/router/index'
|
||||||
|
import {bus} from 'boot/bus'
|
||||||
|
|
||||||
export const sessionName = 'bresSession'
|
export const sessionName = 'bresSession'
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
LoggedIn: false,
|
LoggedIn: false,
|
||||||
|
IsAdmin: false,
|
||||||
Token: '',
|
Token: '',
|
||||||
UsrKSUID: '',
|
UsrKsuid: '',
|
||||||
UsrEmail: '',
|
UsrEmail: '',
|
||||||
UsrFullname: '',
|
UsrFullName: '',
|
||||||
Username: '',
|
Username: '',
|
||||||
|
|
||||||
ClientKSUID: '',
|
ClientKsuid: '',
|
||||||
ClientCode: '',
|
ClientCode: '',
|
||||||
LicenseCode: '',
|
LicenseCode: '',
|
||||||
PkgConf: {}
|
PkgConf: {},
|
||||||
|
|
||||||
|
companyID: null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bus.on('companySelect', (companyID) => {
|
||||||
|
const store = useLoginStore()
|
||||||
|
//store.companyID = companyID
|
||||||
|
store.setCompanyID(companyID)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
export const useLoginStore = defineStore('login', {
|
export const useLoginStore = defineStore('login', {
|
||||||
state: () => {
|
state: () => {
|
||||||
return JSON.parse(JSON.stringify(defaultState))
|
return JSON.parse(JSON.stringify(defaultState))
|
||||||
@@ -27,6 +38,11 @@ export const useLoginStore = defineStore('login', {
|
|||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
|
|
||||||
|
setCompanyID(companyID) {
|
||||||
|
this.companyID = companyID
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
|
|
||||||
login (payload) {
|
login (payload) {
|
||||||
// kaldıysa önceki session'ı uçuralım
|
// kaldıysa önceki session'ı uçuralım
|
||||||
LocalStorage.remove(sessionName)
|
LocalStorage.remove(sessionName)
|
||||||
@@ -57,6 +73,14 @@ export const useLoginStore = defineStore('login', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateProfile (payload) {
|
||||||
|
this.UsrFullName = payload.fullname
|
||||||
|
this.UsrEmail = payload.email
|
||||||
|
this.Username = payload.username
|
||||||
|
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
|
|
||||||
updateState (payload) {
|
updateState (payload) {
|
||||||
Object.assign(this, payload)
|
Object.assign(this, payload)
|
||||||
api.defaults.headers.common['Authorization'] = `Bearer ${payload.Token}`
|
api.defaults.headers.common['Authorization'] = `Bearer ${payload.Token}`
|
||||||
@@ -75,9 +99,17 @@ export const useLoginStore = defineStore('login', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
save () {
|
||||||
|
const pl = {}
|
||||||
|
Object.keys(defaultState).forEach((key) => {
|
||||||
|
pl[key] = this[key]
|
||||||
|
})
|
||||||
|
LocalStorage.set(sessionName, pl)
|
||||||
|
},
|
||||||
|
|
||||||
IsLoggedIn () {
|
IsLoggedIn () {
|
||||||
return this.LoggedIn
|
return this.LoggedIn
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
3284
ui/yarn.lock
Normal file
3284
ui/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user