commit 76e3bdcce16ae96e5ac883b3f2eb8cf29957d584 Author: albert Date: Tue Aug 20 15:50:52 2024 +0200 wip2 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c5e82d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f189433 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +# Variables +IMAGE_NAME = registry.espin.casa/cml04-pbl018 +CONTAINER_NAME = cml04-pbl018 + +# Check if Docker or Podman is available +DOCKER := $(shell command -v docker 2> /dev/null) +PODMAN := $(shell command -v podman 2> /dev/null) + +# Determine which command to use based on availability +ifdef DOCKER + DOCKER_CMD := docker +else ifdef PODMAN + DOCKER_CMD := podman +else +$(error "Neither Docker nor Podman is installed on this system.") +endif + +# Build the Docker image +build: + $(DOCKER_CMD) build -t $(IMAGE_NAME) -f docker/Dockerfile . + +# Run the container +run: + @$(DOCKER_CMD) run $(IMAGE_NAME) + +# Stop and remove the container +stop: + $(DOCKER_CMD) stop $(CONTAINER_NAME) + $(DOCKER_CMD) rm $(CONTAINER_NAME) + +# Remove the Docker image +clean: + $(DOCKER_CMD) rmi $(IMAGE_NAME) \ No newline at end of file diff --git a/ata12.dat b/ata12.dat new file mode 100644 index 0000000..e1fc727 --- /dev/null +++ b/ata12.dat @@ -0,0 +1 @@ +94012345698 \ No newline at end of file diff --git a/ata345.dat b/ata345.dat new file mode 100644 index 0000000..1ce1f90 --- /dev/null +++ b/ata345.dat @@ -0,0 +1 @@ +94512345681 \ No newline at end of file diff --git a/celsa2048.crt b/celsa2048.crt new file mode 100644 index 0000000..523346d --- /dev/null +++ b/celsa2048.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIJANu+mC2Jt3uTMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2Ux +FTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMMWnNjYWxlciBJbmMuMRgw +FgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG9w0BCQEWE3N1cHBvcnRA +enNjYWxlci5jb20wHhcNMTQxMjE5MDAyNzU1WhcNNDIwNTA2MDAyNzU1WjCBoTEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBK +b3NlMRUwEwYDVQQKEwxac2NhbGVyIEluYy4xFTATBgNVBAsTDFpzY2FsZXIgSW5j +LjEYMBYGA1UEAxMPWnNjYWxlciBSb290IENBMSIwIAYJKoZIhvcNAQkBFhNzdXBw +b3J0QHpzY2FsZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +qT7STSxZRTgEFFf6doHajSc1vk5jmzmM6BWuOo044EsaTc9eVEV/HjH/1DWzZtcr +fTj+ni205apMTlKBW3UYR+lyLHQ9FoZiDXYXK8poKSV5+Tm0Vls/5Kb8mkhVVqv7 +LgYEmvEY7HPY+i1nEGZCa46ZXCOohJ0mBEtB9JVlpDIO+nN0hUMAYYdZ1KZWCMNf +5J/aTZiShsorN2A38iSOhdd+mcRM4iNL3gsLu99XhKnRqKoHeH83lVdfu1XBeoQz +z5V6gA3kbRvhDwoIlTBeMa5l4yRdJAfdpkbFzqiwSgNdhbxTHnYYorDzKfr2rEFM +dsMU0DHdeAZf711+1CunuQIDAQABo4IBCjCCAQYwHQYDVR0OBBYEFLm33UrNww4M +hp1d3+wcBGnFTpjfMIHWBgNVHSMEgc4wgcuAFLm33UrNww4Mhp1d3+wcBGnFTpjf +oYGnpIGkMIGhMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8G +A1UEBxMIU2FuIEpvc2UxFTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMM +WnNjYWxlciBJbmMuMRgwFgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG +9w0BCQEWE3N1cHBvcnRAenNjYWxlci5jb22CCQDbvpgtibd7kzAMBgNVHRMEBTAD +AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAw0NdJh8w3NsJu4KHuVZUrmZgIohnTm0j+ +RTmYQ9IKA/pvxAcA6K1i/LO+Bt+tCX+C0yxqB8qzuo+4vAzoY5JEBhyhBhf1uK+P +/WVWFZN/+hTgpSbZgzUEnWQG2gOVd24msex+0Sr7hyr9vn6OueH+jj+vCMiAm5+u +kd7lLvJsBu3AO3jGWVLyPkS3i6Gf+rwAp1OsRrv3WnbkYcFf9xjuaf4z0hRCrLN2 +xFNjavxrHmsH8jPHVvgc1VD0Opja0l/BRVauTrUaoW6tE+wFG5rEcPGS80jjHK4S +pB5iDj2mUZH1T8lzYtuZy0ZPirxmtsk3135+CKNa2OCAhhFjE0xd +-----END CERTIFICATE----- \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..e44d48b --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,9 @@ +package main + +import "git.espin.casa/albert/cml04-plb018/internal/app" + +func main() { + if err := app.Run(); err != nil { + panic(err) + } +} diff --git a/curl b/curl new file mode 100644 index 0000000..98a48f4 --- /dev/null +++ b/curl @@ -0,0 +1 @@ +curl -X POST "http://localhost:3000/api/v1/etiqueta/imprimir" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"DatosEtiqueta\": { \"CoID\": 40155678, \"Colada\": \"CE123456\", \"NrBarras\": \"12\", \"NrEtiquetas\": \"2\", \"NrMatricula\": \"9461234567\", \"Operador\": \"AER\", \"Peso\": 4512.18, \"Turno\": \"A\" }, \"ImpresoraID\": \"NONE\", \"TimeStamp\": \"string\"}" \ No newline at end of file diff --git a/db.sqlite b/db.sqlite new file mode 100644 index 0000000..12d2593 Binary files /dev/null and b/db.sqlite differ diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..3d0e8b7 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,37 @@ +# Etapa de compilación +FROM golang:1.22-bookworm AS builder + +ENV TZ=Europe/Madrid + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ADD celsa2048.crt /usr/local/share/ca-certificates/celsa2048.crt +RUN chmod 644 /usr/local/share/ca-certificates/celsa2048.crt +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates + +RUN update-ca-certificates +WORKDIR /app + +COPY . . + +RUN go get -d -v ./... + +RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -mod=mod -ldflags "-s -w" -o myapp cmd/main.go + +# Etapa de producción + +FROM debian:stable +ENV TZ=Europe/Madrid + +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +ADD celsa2048.crt /usr/local/share/ca-certificates/celsa2048.crt +RUN chmod 644 /usr/local/share/ca-certificates/celsa2048.crt +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates + +RUN update-ca-certificates +WORKDIR /root/ + +COPY --from=builder /app/myapp . + +CMD ["./myapp"] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d2ffe59 --- /dev/null +++ b/go.mod @@ -0,0 +1,24 @@ +module git.espin.casa/albert/cml04-plb018 + +go 1.22.4 + +require ( + git.espin.casa/albert/cml04-eventer v0.0.0-20240508172957-52ca86976f5f + git.espin.casa/albert/logger v0.0.0-20240312060442-59b35e5c6996 + github.com/zc2638/swag v1.6.0 + gorm.io/driver/sqlite v1.5.6 + gorm.io/gorm v1.25.10 +) + +require ( + github.com/golang/snappy v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nsqio/go-nsq v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f424b9e --- /dev/null +++ b/go.sum @@ -0,0 +1,54 @@ +git.espin.casa/albert/cml04-eventer v0.0.0-20240508172957-52ca86976f5f h1:ovKbIJFxABDQhMz+bfZ9eeMrPcs8KINRAIQamFHZrUI= +git.espin.casa/albert/cml04-eventer v0.0.0-20240508172957-52ca86976f5f/go.mod h1:/fj0cTIFEdeYmzL2r4WLEAN2q3N3T48ZPOT1hqusuSI= +git.espin.casa/albert/logger v0.0.0-20240312060442-59b35e5c6996 h1:gOY7u2z9gMOdp0Q1Rod9XvoM0gL84SBXR7n/VxrgvtE= +git.espin.casa/albert/logger v0.0.0-20240312060442-59b35e5c6996/go.mod h1:dacFMi82f5ysDOaJQm0QmQaJZ7mwGFiayJ2iS+JKAfQ= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE= +github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/zc2638/swag v1.6.0 h1:pQ3UE0SeqFKnoOPdBPBMPXVkW+iqODS+ALVh8ZGRyQ0= +github.com/zc2638/swag v1.6.0/go.mod h1:AjyTDUHzZZ4mctSNLEZVD5jWQHFGDJlaCR5XjDm46aE= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= +gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 0000000..bdc6147 --- /dev/null +++ b/internal/app/app.go @@ -0,0 +1,153 @@ +package app + +import ( + "bytes" + "context" + "encoding/json" + "flag" + "os" + "os/signal" + "syscall" + + cml04eventer "git.espin.casa/albert/cml04-eventer" + "git.espin.casa/albert/cml04-plb018/internal/logging" + "git.espin.casa/albert/cml04-plb018/internal/server" + "git.espin.casa/albert/cml04-plb018/internal/service" + "git.espin.casa/albert/cml04-plb018/internal/storage" + "git.espin.casa/albert/cml04-plb018/internal/types" + "git.espin.casa/albert/logger" +) + +func Run() error { + // flags + httpBind := flag.String("bind-addr", ":3000", "http bind address") + nsqAddr := flag.String("nsq-addr", "10.1.152.13", "nsq address") + nsqPort := flag.Int("nsq-port", 4150, "nsq port") + logLevel := flag.String("level", "debug", "Log level") + flag.Parse() + // setup logger + log := logger.New(os.Stdout, *logLevel) + // log fields + logFields := logger.LogFields{ + "http_bind": *httpBind, + "nsq_addr": *nsqAddr, + "nsq_port": *nsqPort, + "log_level": *logLevel, + } + // create subscriber + sub, err := cml04eventer.NewSubscriber(&cml04eventer.SubscriberConfig{ + NSQAddress: *nsqAddr, + NSQPort: *nsqPort, + Unmarshaler: cml04eventer.JSONMarshaler{}, + Channel: "CML04-PLB018", + }, log) + if err != nil { + log.Error("create subscriber failed", err, logFields) + return err + } + defer sub.Close() + // create publisher + pub, err := cml04eventer.NewPublisher(&cml04eventer.PublisherImplConfig{ + NSQAddress: *nsqAddr, + NSQPort: *nsqPort, + Marshaler: cml04eventer.JSONMarshaler{}, + }, log) + if err != nil { + log.Error("create publisher failed", err, logFields) + } + defer pub.Close() + // create context + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + // subscribe events + SapChan, err := sub.SubscribeEvent(ctx, "SAP-IN") + if err != nil { + log.Error("create subscribe event failed", err, logFields) + return err + } + // create storage + storage, err := storage.NewStorage(log) + if err != nil { + log.Error("create storage event failed", err, logFields) + return err + } + // process incoming events + go func() { + for event := range SapChan { + if err := ProcessEvent(ctx, event, storage, log); err != nil { + log.Error("process event has been failed", err, logFields) + continue + } + } + }() + // create service + svc := service.NewService(storage, pub) + // create logging service + svc = logging.NewLogging(svc, log) + // create server + server := server.NewServer(*httpBind, svc) + // start server + server.Start() + // info banner + log.Info("started cml04-pbl018", logFields) + // wait signal to finish + signal := WaitSignal() + log.Info("signal received", logFields.Add(logger.LogFields{ + "signal": signal.String(), + })) + return nil +} + +func ProcessEvent(ctx context.Context, event *cml04eventer.Event, storage storage.Storager, log logger.LoggerAdapter) error { + subject, err := event.EventMeta.Get("subject") + if err != nil { + return err + } + switch subject.(string) { + // production order telegram + case "sap.in.telegramas.z_sms_10001": + log.Info("received production order data from SAP", logger.LogFields{}) + po := &types.ProductionOrder{} + buf := bytes.NewBuffer(event.EventData) + if err := json.NewDecoder(buf).Decode(po); err != nil { + return err + } + return storage.SalvarOrdenProduccion(ctx, po) + // customer order telegram + case "sap.in.telegramas.z_sms_10002": + log.Info("received customer order data from SAP", logger.LogFields{}) + co := &types.CustomerOrder{} + buf := bytes.NewBuffer(event.EventData) + if err := json.NewDecoder(buf).Decode(co); err != nil { + return err + } + return storage.SalvarOrdenCliente(ctx, co) + case "sap.in.calidades": + log.Info("received normas/calidades data from SAP", logger.LogFields{}) + list := &types.NormaList{} + buf := bytes.NewBuffer(event.EventData) + if err := json.NewDecoder(buf).Decode(list); err != nil { + return err + } + return storage.SalvarNormas(ctx, list) + } + return nil +} + +// WaitSignal catching exit signal +func WaitSignal() os.Signal { + ch := make(chan os.Signal, 2) + signal.Notify( + ch, + syscall.SIGINT, + syscall.SIGQUIT, + syscall.SIGTERM, + ) + for { + sig := <-ch + switch sig { + case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM: + return sig + } + } +} diff --git a/internal/helpers/helpers.go b/internal/helpers/helpers.go new file mode 100644 index 0000000..0ac529a --- /dev/null +++ b/internal/helpers/helpers.go @@ -0,0 +1,89 @@ +package helpers + +import ( + "fmt" + "os" + "strconv" + "strings" + "sync" + + "git.espin.casa/albert/cml04-plb018/internal/types" +) + +var ( + mux = sync.RWMutex{} + contador = map[types.PEtiquetado]string{ + types.Ata12: "ata12.dat", + types.Ata345: "ata345.dat", + } +) + +// EsAmericano comprueba si el producto es americano y lo devuelve como boolean +func EsAmericano(producto string) bool { + if strings.HasPrefix(producto, "W") { + return true + } + return false +} + +// MetrosAPies convierte una longitud en metros a pies +func MetrosAPies(m float64) float64 { + return m * 3.28084 +} + +// PiesAMetros convierte una longitud en pies a metros +func PiesAMetros(p float64) float64 { + return p / 3.28084 +} + +// NroPaqueteSiguiente incrementa el contador de paquetes para un puesto de etiquetado +// y lo devuelve como string +func NroPaqueteSiguiente(pe types.PEtiquetado) (string, error) { + mux.Lock() + defer mux.Unlock() + // Read actual value + contador, ok := contador[pe] + if !ok { + return "", fmt.Errorf("puesto de etiquetado desconocido") + } + data, err := os.ReadFile(contador) + if err != nil { + return "", err + } + nm, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return "", err + } + // increase value + nm++ + // Write new matricula value in file + newData := strconv.FormatUint(nm, 10) + // Write new matricula value in file + if err = os.WriteFile(contador, []byte(newData), 0644); err != nil { + return "", err + } + // return new value + return strconv.FormatUint(nm, 10), nil +} + +// NroPaqueteActual devuelve el contador de paquetes para un puesto de etiquetado +// como string +func NroPaqueteActual(pe types.PEtiquetado) (string, error) { + mux.RLock() + defer mux.RUnlock() + // Read actual value + contador, ok := contador[pe] + if !ok { + return "", fmt.Errorf("puesto de etiquetado desconocido") + } + data, err := os.ReadFile(contador) + if err != nil { + return "", err + } + nm, err := strconv.ParseUint(string(data), 10, 64) + if err != nil { + return "", err + } + // return new value + return strconv.FormatUint(nm, 10), nil +} diff --git a/internal/logging/logging.go b/internal/logging/logging.go new file mode 100644 index 0000000..93aaee4 --- /dev/null +++ b/internal/logging/logging.go @@ -0,0 +1,291 @@ +package logging + +import ( + "context" + "time" + + "git.espin.casa/albert/cml04-plb018/internal/service" + "git.espin.casa/albert/cml04-plb018/internal/types" + "git.espin.casa/albert/logger" +) + +type Logging struct { + log logger.LoggerAdapter + next service.IService +} + +// NroPaqueteActual implements service.IService. +func (l *Logging) NroPaqueteActual(ctx context.Context, req *types.NroPaqueteActualReq) (res *types.NroPaqueteActualRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "took": time.Since(start), + } + if err != nil { + l.log.Error("Nro paquete actual failed", err, logFields) + } else { + l.log.Info("Nro paquete actual success", logFields) + } + }(time.Now()) + return l.next.NroPaqueteActual(ctx, req) + +} + +// NroPaqueteSiguiente implements service.IService. +func (l *Logging) NroPaqueteSiguiente(ctx context.Context, req *types.NroPaqueteSiguienteReq) (res *types.NroPaqueteSiguienteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "took": time.Since(start), + } + if err != nil { + l.log.Error("Nro paquete siguiente failed", err, logFields) + } else { + l.log.Info("Nro paquete siguiente success", logFields) + } + }(time.Now()) + return l.next.NroPaqueteSiguiente(ctx, req) +} + +// ImprimirPaqueteRobot implements service.IService. +func (l *Logging) ImprimirPaqueteRobot(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "nro_matricula": req.DatosEtiqueta.NroMatricula, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Imprimir paquete robot failed", err, logFields) + } else { + l.log.Info("Imprimir paquete robot success", logFields) + } + }(time.Now()) + return l.next.ImprimirPaqueteRobot(ctx, req) +} + +// Paquete implements service.IService. +func (l *Logging) Paquete(ctx context.Context, req *types.PaqueteReq) (res *types.PaqueteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "codigo_etiqueta": req.Codigo, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Paquete failed", err, logFields) + } else { + l.log.Info("Paquete success", logFields) + } + }(time.Now()) + return l.next.Paquete(ctx, req) +} + +// Paquetes implements service.IService. +func (l *Logging) Paquetes(ctx context.Context, req *types.PaquetesReq) (res *types.PaquetesRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "inicio": req.Inicio, + "final": req.Final, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Paquetes failed", err, logFields) + } else { + l.log.Info("Paquetes success", logFields) + } + }(time.Now()) + return l.next.Paquetes(ctx, req) +} + +// Etiqueta implements service.IService. +func (l *Logging) Etiqueta(ctx context.Context, req *types.EtiquetaReq) (res *types.EtiquetaRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "codigo_etiqueta": req.Codigo, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Etiqueta failed", err, logFields) + } else { + l.log.Info("Etiqueta success", logFields) + } + }(time.Now()) + return l.next.Etiqueta(ctx, req) +} + +// Etiquetas implements service.IService. +func (l *Logging) Etiquetas(ctx context.Context, req *types.EtiquetasReq) (res *types.EtiquetasRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "took": time.Since(start), + } + if err != nil { + l.log.Error("Etiquetas failed", err, logFields) + } else { + l.log.Info("Etiquetas success", logFields) + } + }(time.Now()) + return l.next.Etiquetas(ctx, req) +} + +// SalvarEtiqueta implements service.IService. +func (l *Logging) SalvarEtiqueta(ctx context.Context, req *types.SalvarEtiquetaReq) (res *types.SalvarEtiquetaRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "codigo_etiqueta": req.Etiqueta.Codigo, + "took": time.Since(start), + } + if err != nil { + l.log.Error("SalvarEtiqueta failed", err, logFields) + } else { + l.log.Info("SalvarEtiqueta success", logFields) + } + }(time.Now()) + return l.next.SalvarEtiqueta(ctx, req) +} + +// SalvarImpresora implements service.IService. +func (l *Logging) SalvarImpresora(ctx context.Context, req *types.SalvarImpresoraReq) (res *types.SalvarImpresoraRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "id_impresora": req.Impresora.ID, + "took": time.Since(start), + } + if err != nil { + l.log.Error("SalvarImpresora failed", err, logFields) + } else { + l.log.Info("SalvarImpresora success", logFields) + } + }(time.Now()) + return l.next.SalvarImpresora(ctx, req) +} + +// Impresora implements service.IService. +func (l *Logging) Impresora(ctx context.Context, req *types.ImpresoraReq) (res *types.ImpresoraRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "id_impresora": req.ID, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Impresora failed", err, logFields) + } else { + l.log.Info("Impresora success", logFields) + } + }(time.Now()) + return l.next.Impresora(ctx, req) +} + +// Impresoras implements service.IService. +func (l *Logging) Impresoras(ctx context.Context, req *types.ImpresorasReq) (res *types.ImpresorasRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "took": time.Since(start), + } + if err != nil { + l.log.Error("Impresoras failed", err, logFields) + } else { + l.log.Info("Impresoras success", logFields) + } + }(time.Now()) + return l.next.Impresoras(ctx, req) +} + +// OrdenesProduccion implements service.IService. +func (l *Logging) OrdenesProduccion(ctx context.Context, req *types.OrdenesProduccionReq) (res *types.OrdenesProduccionRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "limit": req.Limit, + "took": time.Since(start), + } + if err != nil { + l.log.Error("OrdenesProduccion failed", err, logFields) + } else { + l.log.Info("OrdenesProduccion success", logFields) + } + }(time.Now()) + return l.next.OrdenesProduccion(ctx, req) +} + +// OrdenCliente implements service.IService. +func (l *Logging) OrdenCliente(ctx context.Context, req *types.OrdenClienteReq) (res *types.OrdenClienteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "co_id": req.CoID, + "took": time.Since(start), + } + if err != nil { + l.log.Error("OrdenCliente failed", err, logFields) + } else { + l.log.Info("OrdenCliente success", logFields) + } + }(time.Now()) + return l.next.OrdenCliente(ctx, req) +} + +// OrdenProduccion implements service.IService. +func (l *Logging) OrdenProduccion(ctx context.Context, req *types.OrdenProduccionReq) (res *types.OrdenProduccionRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "po_id": req.PoID, + "took": time.Since(start), + } + if err != nil { + l.log.Error("OrdenProduccion failed", err, logFields) + } else { + l.log.Info("OrdenProduccion success", logFields) + } + }(time.Now()) + return l.next.OrdenProduccion(ctx, req) +} + +// OrdenesCliente implements service.IService. +func (l *Logging) OrdenesCliente(ctx context.Context, req *types.OrdenesClienteReq) (res *types.OrdenesClienteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "po_id": req.PoID, + "took": time.Since(start), + } + if err != nil { + l.log.Error("OrdenesCliente failed", err, logFields) + } else { + l.log.Info("OrdenesCliente success", logFields) + } + }(time.Now()) + return l.next.OrdenesCliente(ctx, req) +} + +// Normas implements service.IService. +func (l *Logging) Normas(ctx context.Context, req *types.NormasReq) (res *types.NormasRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "code": req.Codigo, + "took": time.Since(start), + } + if err != nil { + l.log.Error("Normas failed", err, logFields) + } else { + l.log.Info("Normas success", logFields) + } + }(time.Now()) + return l.next.Normas(ctx, req) +} + +// ImprimirPaquete implements service.IService. +func (l *Logging) ImprimirPaquete(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) { + defer func(start time.Time) { + logFields := logger.LogFields{ + "took": time.Since(start), + } + if err != nil { + l.log.Error("imprimir etiqueta failed", err, logFields) + } else { + l.log.Info("imprimir etiqueta success", logFields) + } + }(time.Now()) + return l.next.ImprimirPaquete(ctx, req) +} + +func NewLogging(svc service.IService, log logger.LoggerAdapter) service.IService { + return &Logging{ + log: log, + next: svc, + } +} diff --git a/internal/server/server.go b/internal/server/server.go new file mode 100644 index 0000000..0dd959e --- /dev/null +++ b/internal/server/server.go @@ -0,0 +1,682 @@ +package server + +import ( + "encoding/json" + "fmt" + "net/http" + "path" + "time" + + "git.espin.casa/albert/cml04-plb018/internal/service" + "git.espin.casa/albert/cml04-plb018/internal/types" + "github.com/zc2638/swag" + "github.com/zc2638/swag/endpoint" + "github.com/zc2638/swag/option" +) + +type Server struct { + svc service.IService + api *swag.API + url string +} + +func NroMatriculaSiguienteEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/nromatricula/next", + endpoint.BodyR(types.NroPaqueteSiguienteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.NroPaqueteSiguienteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene el numero de matricula siguiente"), + endpoint.Description("Obtiene el numero de matricula siguiente"), + endpoint.Handler(NroMatriculaSiguienteHandler(svc)), + ) +} + +func NroMatriculaSiguienteHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.NroPaqueteSiguienteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + // call service + res, err := svc.NroPaqueteSiguiente(r.Context(), req) + if err != nil { + http.Error(w, fmt.Sprintf("PaquetesHandler failed: %s", err.Error()), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func NroMatriculaActualEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/nromatricula/get", + endpoint.BodyR(types.NroPaqueteActualReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.NroPaqueteActualReq{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene el numero de matricula actual"), + endpoint.Description("Obtiene el numero de matricula actual"), + endpoint.Handler(NroMatriculaActualHandler(svc)), + ) +} + +func NroMatriculaActualHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.NroPaqueteActualReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + // call service + res, err := svc.NroPaqueteActual(r.Context(), req) + if err != nil { + http.Error(w, fmt.Sprintf("PaquetesHandler failed: %s", err.Error()), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func PaquetesEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/paquete/list", + endpoint.BodyR(types.PaquetesReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.PaquetesRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene el numero de matricula actual"), + endpoint.Description("Obtiene el numero de matricula actual"), + endpoint.Handler(PaquetesHandler(svc)), + ) +} + +func PaquetesHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.PaquetesReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + // call service + res, err := svc.Paquetes(r.Context(), req) + if err != nil { + http.Error(w, fmt.Sprintf("PaquetesHandler failed: %s", err.Error()), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func PaqueteEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/paquete/get", + endpoint.BodyR(types.PaqueteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.PaqueteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene los datos del paquete (bulto)"), + endpoint.Description("Obtiene los datos del paquete (bulto)"), + endpoint.Handler(PaqueteHandler(svc)), + ) +} + +func PaqueteHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.PaqueteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + // call service + res, err := svc.Paquete(r.Context(), req) + if err != nil { + http.Error(w, fmt.Sprintf("PaqueteHandler failed: %s", err.Error()), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func EtiquetasEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/etiqueta/list", + endpoint.BodyR(types.EtiquetasReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.EtiquetasRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene los datos de las etiquetas"), + endpoint.Description("Obtiene los datos de las etiquetas"), + endpoint.Handler(EtiquetasHandler(svc)), + ) +} + +func EtiquetasHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.EtiquetasReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + // call service + res, err := svc.Etiquetas(r.Context(), req) + if err != nil { + http.Error(w, fmt.Sprintf("EtiquetasHandler failed: %s", err.Error()), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func EtiquetaEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/etiqueta/get", + endpoint.BodyR(types.EtiquetaReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.EtiquetaRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene los datos de la etiqueta"), + endpoint.Description("Obtiene los datos de la etiqueta"), + endpoint.Handler(EtiquetaHandler(svc)), + ) +} + +func EtiquetaHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.EtiquetaReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.Etiqueta(r.Context(), req) + if err != nil { + http.Error(w, "etiqueta handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func SalvarEtiquetaEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/etiqueta/create", + endpoint.BodyR(types.SalvarEtiquetaReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.SalvarEtiquetaRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Salva los datos de la etiqueta"), + endpoint.Description("Salva los datos de la etiqueta"), + endpoint.Handler(SalvarEtiquetaHandler(svc)), + ) +} + +func SalvarEtiquetaHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.SalvarEtiquetaReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.SalvarEtiqueta(r.Context(), req) + if err != nil { + http.Error(w, "salva datos etiqueta handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func SalvarImpresorasEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/impresora/create", + endpoint.BodyR(types.SalvarImpresoraReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.SalvarImpresoraRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Salva los datos de la impresora"), + endpoint.Description("Salva los datos de la impresora"), + endpoint.Handler(SalvarImpresoraHandler(svc)), + ) +} + +func SalvarImpresoraHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.SalvarImpresoraReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.SalvarImpresora(r.Context(), req) + if err != nil { + http.Error(w, "salva datos impresora handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func ImpresorasEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/impresora/list", + endpoint.BodyR(types.ImpresorasReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.ImpresorasRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene los datos de las impresoras"), + endpoint.Description("Obtiene los datos de las impresoras"), + endpoint.Handler(ImpresorasHandler(svc)), + ) +} + +func ImpresorasHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.ImpresorasReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.Impresoras(r.Context(), req) + if err != nil { + http.Error(w, "obtiene datos de las impresoras handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func ImpresoraEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/impresora/get", + endpoint.BodyR(types.ImpresoraReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.ImpresoraRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtiene los datos de la impresora"), + endpoint.Description("Obtiene los datos de la impresora"), + endpoint.Handler(ImpresoraHandler(svc)), + ) +} + +func ImpresoraHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.ImpresoraReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.Impresora(r.Context(), req) + if err != nil { + http.Error(w, "obtiene datos impresora handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func OrdenesClientesEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/co/list", + endpoint.BodyR(types.OrdenesClienteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.OrdenesClienteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtener lista de Ordenes de cliente"), + endpoint.Description("Obtener lista de Ordenes de cliente"), + endpoint.Handler(OrdenesClienteHandler(svc)), + ) +} + +func OrdenesClienteHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.OrdenesClienteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.OrdenesCliente(r.Context(), req) + if err != nil { + http.Error(w, "obtiene ordenes de cliente handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func OrdenClienteEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/co/get", + endpoint.BodyR(types.OrdenClienteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.OrdenClienteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtener lista de Ordenes de cliente"), + endpoint.Description("Obtener lista de Ordenes de cliente"), + endpoint.Handler(OrdenClienteHandler(svc)), + ) +} + +func OrdenClienteHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.OrdenClienteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.OrdenCliente(r.Context(), req) + if err != nil { + http.Error(w, "obtiene ordenes de cliente handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func OrdenesProduccionEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/po/list", + endpoint.BodyR(types.OrdenesProduccionReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.OrdenesProduccionRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtener lista de Ordenes de producción"), + endpoint.Description("Obtener lista de Ordenes de producción"), + endpoint.Handler(OrdenesProduccionHandler(svc)), + ) +} + +func OrdenesProduccionHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.OrdenesProduccionReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.OrdenesProduccion(r.Context(), req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func OrdenProduccionEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/po/get", + endpoint.BodyR(types.OrdenProduccionReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.OrdenProduccionRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Obtener datos de la Orden de producción basado en el identificador"), + endpoint.Description("Obtener datos de la Orden de producción basado en el identificador"), + endpoint.Handler(OrdenProduccionHandler(svc)), + ) +} + +func OrdenProduccionHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.OrdenProduccionReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.OrdenProduccion(r.Context(), req) + if err != nil { + http.Error(w, "obtiene orden de produccion by id datos handler failed", http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func ImprimirPaqueteRobotEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/robot/print", + endpoint.BodyR(types.ImprimirPaqueteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.ImprimirPaqueteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Imprimir paquete"), + endpoint.Description("Imprimir paquete"), + endpoint.Handler(ImprimirPaqueteRobotHandler(svc)), + ) +} + +func ImprimirPaqueteRobotHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.ImprimirPaqueteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.ImprimirPaqueteRobot(r.Context(), req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func ImprimirEtiquetaEndPoint(svc service.IService) *swag.Endpoint { + return endpoint.New(http.MethodPost, "/paquete/print", + endpoint.BodyR(types.ImprimirPaqueteReq{}), + endpoint.ResponseSuccess(endpoint.SchemaResponseOption(types.ImprimirPaqueteRes{})), + endpoint.Response(http.StatusInternalServerError, "process internal error", endpoint.SchemaResponseOption("")), + endpoint.Summary("Imprimir paquete"), + endpoint.Description("Imprimir paquete"), + endpoint.Handler(ImprimirEtiquetaHandler(svc)), + ) +} + +func ImprimirEtiquetaHandler(svc service.IService) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // request body holder + req := &types.ImprimirPaqueteReq{} + // decode json body request + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, "body json decoding failed", http.StatusBadRequest) + return + } + res, err := svc.ImprimirPaquete(r.Context(), req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // set content type header + w.Header().Set("Content-Type", "application/json") + // response + w.WriteHeader(http.StatusOK) + // write response + if err := json.NewEncoder(w).Encode(&res); err != nil { + http.Error(w, "encode response failed", http.StatusInternalServerError) + return + } + }) +} + +func (s *Server) Start() error { + // set api handlers + for p, endpoints := range s.api.Paths { + http.DefaultServeMux.Handle(path.Join(s.api.BasePath, p), endpoints) + } + // set swagger handlers + http.DefaultServeMux.Handle("/swagger/json", s.api.Handler()) + patterns := swag.UIPatterns("/swagger/ui") + for _, pattern := range patterns { + http.DefaultServeMux.Handle(pattern, swag.UIHandler("/swagger/ui", "/swagger/json", true)) + } + // Crear un servidor HTTP + server := http.Server{ + Addr: s.url, + ReadTimeout: 5 * time.Second, // time limit for reading + WriteTimeout: 5 * time.Second, // time limit for writting + IdleTimeout: 5 * time.Second, + } + // start api + go func() { + if err := server.ListenAndServe(); err != nil { + panic(err) + } + }() + return nil +} + +func NewServer(url string, svc service.IService) *Server { + // create new swag + api := swag.New( + option.Title("CELSA 4 Plb018 API Server"), + option.Description("This is an implementation of a REST API server for Plb18"), + option.ContactEmail("aespin@gcelsa.com"), + option.Version("1.0"), + option.BasePath("/api/v1"), + option.License("MIT", "https://opensource.org/license/mit"), + ) + // add end points + api.AddEndpoint( + ImprimirEtiquetaEndPoint(svc), + ImprimirPaqueteRobotEndPoint(svc), + EtiquetaEndPoint(svc), + EtiquetasEndPoint(svc), + SalvarEtiquetaEndPoint(svc), + OrdenProduccionEndPoint(svc), + OrdenesProduccionEndPoint(svc), + OrdenClienteEndPoint(svc), + OrdenesClientesEndPoint(svc), + ImpresoraEndPoint(svc), + ImpresorasEndPoint(svc), + SalvarImpresorasEndPoint(svc), + PaqueteEndPoint(svc), + PaquetesEndPoint(svc), + NroMatriculaActualEndPoint(svc), + NroMatriculaSiguienteEndPoint(svc), + ) + // return new server + return &Server{ + svc: svc, + api: api, + url: url, + } +} diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..72500f1 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,510 @@ +package service + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net" + "strconv" + "strings" + "sync" + "time" + + cml04eventer "git.espin.casa/albert/cml04-eventer" + "git.espin.casa/albert/cml04-plb018/internal/helpers" + "git.espin.casa/albert/cml04-plb018/internal/storage" + "git.espin.casa/albert/cml04-plb018/internal/types" + + "gorm.io/gorm" +) + +var ( + NSQTOPIC = map[types.Robot]string{ + types.Robot12: "ROBOT12", + types.Robot345: "ROBOT345", + } +) + +type IService interface { + // Etiquetas + Etiqueta(ctx context.Context, req *types.EtiquetaReq) (res *types.EtiquetaRes, err error) + Etiquetas(ctx context.Context, req *types.EtiquetasReq) (res *types.EtiquetasRes, err error) + SalvarEtiqueta(ctx context.Context, req *types.SalvarEtiquetaReq) (res *types.SalvarEtiquetaRes, err error) + // Normas + Normas(ctx context.Context, req *types.NormasReq) (res *types.NormasRes, err error) + // Orden Produccion + OrdenProduccion(ctx context.Context, req *types.OrdenProduccionReq) (res *types.OrdenProduccionRes, err error) + OrdenesProduccion(ctx context.Context, req *types.OrdenesProduccionReq) (res *types.OrdenesProduccionRes, err error) + // Orden Cliente + OrdenCliente(ctx context.Context, req *types.OrdenClienteReq) (res *types.OrdenClienteRes, err error) + OrdenesCliente(ctx context.Context, req *types.OrdenesClienteReq) (res *types.OrdenesClienteRes, err error) + // Impresora + Impresora(ctx context.Context, req *types.ImpresoraReq) (res *types.ImpresoraRes, err error) + Impresoras(ctx context.Context, req *types.ImpresorasReq) (res *types.ImpresorasRes, err error) + SalvarImpresora(ctx context.Context, req *types.SalvarImpresoraReq) (res *types.SalvarImpresoraRes, err error) + // Paquetes + Paquete(ctx context.Context, req *types.PaqueteReq) (res *types.PaqueteRes, err error) + Paquetes(ctx context.Context, req *types.PaquetesReq) (res *types.PaquetesRes, err error) + ImprimirPaquete(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) + ImprimirPaqueteRobot(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) + // Nro Paquetes + NroPaqueteActual(ctx context.Context, req *types.NroPaqueteActualReq) (res *types.NroPaqueteActualRes, err error) + NroPaqueteSiguiente(ctx context.Context, req *types.NroPaqueteSiguienteReq) (res *types.NroPaqueteSiguienteRes, err error) +} + +type service struct { + pub cml04eventer.Publisher + storage storage.Storager + mux *sync.Mutex +} + +// NroPaqueteActual implements IService. +func (s *service) NroPaqueteActual(ctx context.Context, req *types.NroPaqueteActualReq) (res *types.NroPaqueteActualRes, err error) { + nroMatricula, err := helpers.NroPaqueteActual(req.PEtiquetado) + if err != nil { + return nil, err + } + return &types.NroPaqueteActualRes{ + NroMatricula: nroMatricula, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// NroPaqueteSiguiente implements IService. +func (s *service) NroPaqueteSiguiente(ctx context.Context, req *types.NroPaqueteSiguienteReq) (res *types.NroPaqueteSiguienteRes, err error) { + nroMatricula, err := helpers.NroPaqueteSiguiente(req.PEtiquetado) + if err != nil { + return nil, err + } + return &types.NroPaqueteSiguienteRes{ + NroMatricula: nroMatricula, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// ImprimirPaqueteRobot implements IService. +func (s *service) ImprimirPaqueteRobot(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) { + // create buffer + buff := bytes.Buffer{} + // encode request + if err := json.NewEncoder(&buff).Encode(req); err != nil { + return nil, err + } + // get nsq robot topic + topic, ok := NSQTOPIC[req.Robot] + if !ok { + return nil, fmt.Errorf("robot topic not found") + } + // create meta header event + meta := cml04eventer.NewMetaData() + // set subjet + meta.Set("subject", "pbl018.print.data") + // create event + event := cml04eventer.NewEvent("PLB018", topic, meta, buff.Bytes()) + // publish event + if err := s.pub.PublishEvent(event); err != nil { + return nil, err + } + // crear paquete + paquete, err := s.CrearDatosPaquete(ctx, req) + if err != nil { + return nil, err + } + // guardar paquete + if err := s.SalvarPaquete(ctx, paquete); err != nil { + return nil, err + } + // return response + return &types.ImprimirPaqueteRes{ + Respuesta: fmt.Sprintf("imprimir paquete [%s] mediante robot finalizó con éxito", req.DatosEtiqueta.NroMatricula), + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Paquete implements IService. +func (s *service) Paquete(ctx context.Context, req *types.PaqueteReq) (res *types.PaqueteRes, err error) { + paquete, err := s.storage.Paquete(ctx, req.Codigo) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.PaqueteRes{ + Paquete: paquete, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Paquetes implements IService. +func (s *service) Paquetes(ctx context.Context, req *types.PaquetesReq) (res *types.PaquetesRes, err error) { + inicio, err := time.Parse("02/01/2006 15:04:05", req.Inicio) + if err != nil { + return nil, err + } + final, err := time.Parse("02/01/2006 15:04:05", req.Final) + if err != nil { + return nil, err + } + paquetes, err := s.storage.Paquetes(ctx, inicio, final) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.PaquetesRes{ + Paquetes: paquetes, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Etiqueta implements IService. +func (s *service) Etiqueta(ctx context.Context, req *types.EtiquetaReq) (res *types.EtiquetaRes, err error) { + etiqueta, err := s.storage.Etiqueta(ctx, req.Codigo) + if err != nil { + return nil, err + } + return &types.EtiquetaRes{ + Etiqueta: etiqueta, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Etiquetas implements IService. +func (s *service) Etiquetas(ctx context.Context, req *types.EtiquetasReq) (res *types.EtiquetasRes, err error) { + // get etiquetas + etiquetas, err := s.storage.Etiquetas(ctx) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.EtiquetasRes{ + Etiquetas: etiquetas, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +func (s *service) SalvarEtiqueta(ctx context.Context, req *types.SalvarEtiquetaReq) (res *types.SalvarEtiquetaRes, err error) { + if err := s.storage.SalvarEtiqueta(ctx, req.Etiqueta); err != nil { + return nil, err + } + // return response + return &types.SalvarEtiquetaRes{ + Respuesta: fmt.Sprintf("save label: %s success", req.Etiqueta.Codigo), + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// SalvarImpresora implements IService. +func (s *service) SalvarImpresora(ctx context.Context, req *types.SalvarImpresoraReq) (res *types.SalvarImpresoraRes, err error) { + if err := s.storage.SalvarImpresora(ctx, req.Impresora); err != nil { + return nil, err + } + // return response + return &types.SalvarImpresoraRes{ + Message: fmt.Sprintf("save printer: %s success", req.Impresora.ID), + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Impresora implements IService. +func (s *service) Impresora(ctx context.Context, req *types.ImpresoraReq) (res *types.ImpresoraRes, err error) { + // get impresora + zebra, err := s.storage.Impresora(ctx, req.ID) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.ImpresoraRes{ + Impresora: zebra, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Impresoras implements IService. +func (s *service) Impresoras(ctx context.Context, req *types.ImpresorasReq) (res *types.ImpresorasRes, err error) { + // get impresoras + zebras, err := s.storage.Impresoras(ctx) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.ImpresorasRes{ + Impresoras: zebras, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, err +} + +// OrdenesProduccion implements IService. +func (s *service) OrdenesProduccion(ctx context.Context, req *types.OrdenesProduccionReq) (res *types.OrdenesProduccionRes, err error) { + // get ordenes produccion + pos, err := s.storage.OrdenesProduccion(ctx, req.Limit) + // handle error + if err != nil { + return nil, err + } + // return response + return &types.OrdenesProduccionRes{ + OrdenesProduccion: pos, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// OrdenesCliente implements IService. +func (s *service) OrdenesCliente(ctx context.Context, req *types.OrdenesClienteReq) (res *types.OrdenesClienteRes, err error) { + // get ordenes clientes + cos, err := s.storage.OrdenesCliente(ctx, req.PoID) + // handle error + if err != nil { + return nil, err + } + return &types.OrdenesClienteRes{OrdenesCliente: cos, TimeStamp: time.Now().UTC().Format(time.RFC3339)}, nil +} + +// OrdenCliente implements IService. +func (s *service) OrdenCliente(ctx context.Context, req *types.OrdenClienteReq) (res *types.OrdenClienteRes, err error) { + // get orden cliente + co, err := s.storage.OrdenCliente(ctx, req.CoID) + // handle error + if err != nil { + return nil, err + } + return &types.OrdenClienteRes{ + OrdenCliente: co, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// OrdenProduccion implements IService. +func (s *service) OrdenProduccion(ctx context.Context, req *types.OrdenProduccionReq) (res *types.OrdenProduccionRes, err error) { + // get orden produccion + po, err := s.storage.OrdenProduccion(ctx, req.PoID) + if err != nil { + return nil, err + } + return &types.OrdenProduccionRes{ + OrdenProduccion: po, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +// Normas implements IService. +func (s *service) Normas(ctx context.Context, req *types.NormasReq) (res *types.NormasRes, err error) { + normas, err := s.storage.Normas(ctx, req.Codigo) + if err != nil { + return nil, err + } + return &types.NormasRes{ + Normas: normas, + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +func TipoEtiqueta(producto string) types.EtiquetaTipo { + if strings.HasPrefix(producto, "W") { + return types.EtiquetaAmericana + } else if strings.HasPrefix(producto, "UB") || strings.HasPrefix(producto, "UC") || strings.HasPrefix(producto, "UPF") { + return types.EtiquetaBritanica + } else { + return types.EtiquetaEuropea + } +} + +func (s *service) SalvarPaquete(ctx context.Context, paquete *types.Paquete) error { + // check if bundle already exists + _, err := s.storage.Paquete(ctx, paquete.NroPaquete) + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + // doesn't exists create it! + return s.CrearPaquete(ctx, paquete) + } else { + // error + return err + } + } else { + // exists update it! + return s.storage.ActualizarPaquete(ctx, paquete) + } +} + +func (s *service) CrearDatosPaquete(ctx context.Context, req *types.ImprimirPaqueteReq) (*types.Paquete, error) { + // get orden cliente + co, err := s.storage.OrdenCliente(ctx, req.DatosEtiqueta.CoID) + if err != nil { + return nil, err + } + // get material code + matnr := co.MaterCode + // get norma code + matnr = strings.Split(matnr, "-")[0] + // get normas + normas, err := s.storage.Normas(ctx, matnr) + if err != nil { + return nil, err + } + // get production order + po, err := s.storage.OrdenProduccion(ctx, co.POrderNo) + if err != nil { + return nil, err + } + // barras + barras, err := strconv.Atoi(req.DatosEtiqueta.NrBarras) + if err != nil { + return nil, err + } + // get longitud + longitud, err := strconv.ParseFloat(co.OrdLen, 64) + if err != nil { + return nil, err + } + longitud = longitud / 1000 + // create bundle data + return &types.Paquete{ + NroPaquete: req.DatosEtiqueta.NroMatricula, + OrdenProduccion: po.POrderNo, + OrdenCliente: co.COrderNo, + Producto: po.FSection, + Colada: req.DatosEtiqueta.Colada, + Calidad: normas.Calidad, + Matnr: co.MaterCode, + Operador: req.DatosEtiqueta.Operador, + Turno: req.DatosEtiqueta.Turno, + Longitud: longitud, + Barras: uint8(barras), + Peso: req.DatosEtiqueta.Peso, + PesoTeorico: req.DatosEtiqueta.PesoTeorico, + Normed: normas.NormaMedida, + Norpro: normas.NormaProducto, + Nortol: normas.NormaTolerancia, + DesvioPeso: req.DatosEtiqueta.DesvioPeso, + Confirmado: false, + Procesado: false, + Observaciones: "", + Reclasificado: false, + }, nil +} + +// ImprimirPaquete implements IService. +func (s *service) ImprimirPaquete(ctx context.Context, req *types.ImprimirPaqueteReq) (res *types.ImprimirPaqueteRes, err error) { + // crear datos paq + paquete, err := s.CrearDatosPaquete(ctx, req) + if err != nil { + return nil, err + } + // salvar paquete + if err := s.SalvarPaquete(ctx, paquete); err != nil { + return nil, err + } + // create label zpl code + contenido, err := s.CrearEtiqueta( + ctx, + req.DatosEtiqueta.NroMatricula, + // convert longitud to string + strconv.FormatFloat(paquete.Longitud, 'f', 2, 64), + req.DatosEtiqueta.Colada, + paquete.Normed, + paquete.Norpro, + paquete.Nortol, + paquete.Calidad, + time.Now().Format("02/01/2006"), + req.DatosEtiqueta.NrBarras, + paquete.Producto, + req.DatosEtiqueta.NrEtiquetas, + TipoEtiqueta(paquete.Producto), + ) + // handle error + if err != nil { + return nil, err + } + // imprimir + if err := s.Imprimir(ctx, contenido, req.ImpresoraID); err != nil { + return nil, err + } + // return response + return &types.ImprimirPaqueteRes{ + Respuesta: "imprimir etiqueta success", + TimeStamp: time.Now().UTC().Format(time.RFC3339), + }, nil +} + +func (s *service) CrearPaquete(ctx context.Context, paquete *types.Paquete) error { + return s.storage.SalvarPaquete(ctx, paquete) +} + +func (s *service) ActualizarPaquete(ctx context.Context, paquete *types.Paquete) error { + return s.storage.ActualizarPaquete(ctx, paquete) +} + +func (s *service) CrearEtiqueta(ctx context.Context, nroMatricula, longitud, colada, normaa, normab, normac, calidad, fecha, barras, producto, nroEtis string, tipo types.EtiquetaTipo) ([]byte, error) { + // get formato + formato, ok := types.TipoFormato[tipo] + if !ok { + return nil, fmt.Errorf("tipo formato etiqueta no existe") + } + // get etiqueta + etiqueta, err := s.storage.Etiqueta(ctx, formato) + if err != nil { + return nil, err + } + // si el producto es americano la longitud se convierte a pies + if helpers.EsAmericano(producto) { + // convertir longitud a pies + l, err := strconv.ParseFloat(longitud, 64) + if err != nil { + return nil, err + } + longitud = strconv.FormatFloat(l, 'f', 2, 64) + } + // replace all template with label data + contenido := etiqueta.Contenido + contenido = strings.ReplaceAll(contenido, "9999999999", nroMatricula) + contenido = strings.ReplaceAll(contenido, "{{longitud}}", longitud) + contenido = strings.ReplaceAll(contenido, "{{colada}}", colada) + contenido = strings.ReplaceAll(contenido, "{{normaA}}", normaa) + contenido = strings.ReplaceAll(contenido, "{{normaB}}", normab) + contenido = strings.ReplaceAll(contenido, "{{normaC}}", normac) + contenido = strings.ReplaceAll(contenido, "{{calidad}}", calidad) + contenido = strings.ReplaceAll(contenido, "{{fecha}}", fecha) + contenido = strings.ReplaceAll(contenido, "{{barras}}", barras) + contenido = strings.ReplaceAll(contenido, "{{producto}}", producto) + contenido = strings.ReplaceAll(contenido, "{{etiquetas}}", nroEtis) + // return + return []byte(contenido), nil +} + +func (s *service) Imprimir(ctx context.Context, data []byte, ImpresoraID string) error { + if strings.ToUpper(ImpresoraID) == "NONE" { + return nil + } + s.mux.Lock() + defer s.mux.Unlock() + impresora, err := s.storage.Impresora(ctx, ImpresoraID) + if err != nil { + return err + } + // connect to printer + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", impresora.Address, impresora.Port)) + if err != nil { + return err + } + // close connection + defer conn.Close() + // send data + _, err = conn.Write(data) + if err != nil { + return err + } + return nil +} + +func NewService(storage storage.Storager, pub cml04eventer.Publisher) IService { + return &service{ + pub: pub, + storage: storage, + mux: &sync.Mutex{}, + } +} diff --git a/internal/storage/storage.go b/internal/storage/storage.go new file mode 100644 index 0000000..29f334e --- /dev/null +++ b/internal/storage/storage.go @@ -0,0 +1,241 @@ +package storage + +import ( + "context" + "fmt" + "sync" + "time" + + "git.espin.casa/albert/cml04-plb018/internal/types" + "git.espin.casa/albert/logger" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +type Storager interface { + // Normas + Normas(ctx context.Context, codigo string) (*types.Normas, error) + SalvarNormas(ctx context.Context, etiqueta *types.NormaList) error + // Ordenes produccion + OrdenProduccion(ctx context.Context, po int) (*types.ProductionOrder, error) + OrdenesProduccion(ctx context.Context, limit int) ([]types.ProductionOrder, error) + SalvarOrdenProduccion(ctx context.Context, po *types.ProductionOrder) error + // Ordenes cliente + OrdenCliente(ctx context.Context, co int) (*types.CustomerOrder, error) + OrdenesCliente(ctx context.Context, po int) ([]types.CustomerOrder, error) + SalvarOrdenCliente(ctx context.Context, co *types.CustomerOrder) error + // Impresoras + Impresora(ctx context.Context, id string) (*types.Zebra, error) + Impresoras(ctx context.Context) ([]types.Zebra, error) + SalvarImpresora(ctx context.Context, zebra *types.Zebra) error + // Etiquetas + Etiqueta(ctx context.Context, id string) (*types.Label, error) + Etiquetas(ctx context.Context) ([]types.Label, error) + SalvarEtiqueta(ctx context.Context, label *types.Label) error + // Paquetes + Paquete(ctx context.Context, id string) (*types.Paquete, error) + Paquetes(ctx context.Context, inicio, final time.Time) ([]types.Paquete, error) + SalvarPaquete(ctx context.Context, paquete *types.Paquete) error + ActualizarPaquete(ctx context.Context, paquete *types.Paquete) error +} + +type storage struct { + db *gorm.DB + mux *sync.RWMutex + log logger.LoggerAdapter +} + +// ActualizarPaquete implements Storager. +func (s *storage) ActualizarPaquete(ctx context.Context, paquete *types.Paquete) error { + return s.db.Model(&types.Paquete{}).Where("nro_paquete = ?", paquete.NroPaquete).Updates(types.Paquete{ + NroPaquete: paquete.NroPaquete, + OrdenProduccion: paquete.OrdenProduccion, + OrdenCliente: paquete.OrdenCliente, + Producto: paquete.Producto, + Colada: paquete.Colada, + Calidad: paquete.Calidad, + Matnr: paquete.Matnr, + Operador: paquete.Operador, + Turno: paquete.Turno, + Longitud: paquete.Longitud, + Barras: paquete.Barras, + Peso: paquete.Peso, + PesoTeorico: paquete.PesoTeorico, + Normed: paquete.Normed, + Norpro: paquete.Norpro, + Nortol: paquete.Nortol, + DesvioPeso: paquete.DesvioPeso, + Confirmado: true, + Procesado: false, + Observaciones: fmt.Sprintf("reclasificado por: %s en fecha: %s", paquete.Operador, time.Now().Format("02/01/2006 15:04")), + Reclasificado: true, + UpdatedAt: time.Now(), + }).Error +} + +// Paquete implements Storager. +func (s *storage) Paquete(ctx context.Context, id string) (*types.Paquete, error) { + paquete := &types.Paquete{} + if err := s.db.Where("nro_paquete = ?", id).First(paquete).Error; err != nil { + return nil, err + } + return paquete, nil +} + +// Paquetes implements Storager. +func (s *storage) Paquetes(ctx context.Context, inicio time.Time, final time.Time) ([]types.Paquete, error) { + paquetes := []types.Paquete{} + // get paquetes + if err := s.db.Where("created_at BETWEEN ? AND ?", inicio, final).Find(&paquetes).Error; err != nil { + return nil, err + } + return paquetes, nil +} + +// SalvarPaquete implements Storager. +func (s *storage) SalvarPaquete(ctx context.Context, paquete *types.Paquete) error { + return s.db.Create(paquete).Error +} + +// Etiquetas implements Storager. +func (s *storage) Etiquetas(ctx context.Context) ([]types.Label, error) { + etiquetas := []types.Label{} + if err := s.db.Order("codigo asc").Find(&etiquetas).Error; err != nil { + return nil, err + } + return etiquetas, nil +} + +// Etiqueta implements Storager. +func (s *storage) Etiqueta(ctx context.Context, id string) (*types.Label, error) { + etiqueta := &types.Label{} + // get etiqueta + if err := s.db.Where("codigo = ?", id).First(etiqueta).Error; err != nil { + return nil, err + } + return etiqueta, nil +} + +// SalvarEtiqueta implements Storager. +func (s *storage) SalvarEtiqueta(ctx context.Context, label *types.Label) error { + return s.db.Save(label).Error +} + +// SalvarNormas implements Storager. +func (s *storage) SalvarNormas(ctx context.Context, normas *types.NormaList) error { + for _, norma := range normas.Lista { + if err := s.db.Save(&norma).Error; err != nil { + return err + } + } + return nil +} + +// Impresora implements Storager. +func (s *storage) Impresora(ctx context.Context, id string) (*types.Zebra, error) { + zebra := &types.Zebra{} + if err := s.db.Where("id = ?", id).First(zebra).Error; err != nil { + return nil, err + } + return zebra, nil +} + +// Impresoras implements Storager. +func (s *storage) Impresoras(ctx context.Context) ([]types.Zebra, error) { + zebras := []types.Zebra{} + if err := s.db.Order("id asc").Find(&zebras).Error; err != nil { + return nil, err + } + return zebras, nil +} + +// SalvarImpresora implements Storager. +func (s *storage) SalvarImpresora(ctx context.Context, zebra *types.Zebra) error { + return s.db.Save(zebra).Error +} + +// OrdenesProduccion implements Storager. +func (s *storage) OrdenesProduccion(ctx context.Context, limit int) ([]types.ProductionOrder, error) { + poos := []types.ProductionOrder{} + // get production orders + if err := s.db.Order("p_order_no desc").Limit(limit).Find(&poos).Error; err != nil { + return nil, err + } + return poos, nil +} + +// Normas implements Storager. +func (s *storage) Normas(ctx context.Context, codigo string) (*types.Normas, error) { + normas := &types.Normas{} + // get normas + if err := s.db.Where("codigo = ?", codigo).First(normas).Error; err != nil { + return nil, err + } + return normas, nil +} + +// OrdenCliente implements Storager. +func (s *storage) OrdenCliente(ctx context.Context, co int) (*types.CustomerOrder, error) { + coo := &types.CustomerOrder{} + // get customer order + if err := s.db.Where("c_order_no=?", co).First(coo).Error; err != nil { + return nil, err + } + return coo, nil +} + +// OrdenProduccion implements Storager. +func (s *storage) OrdenProduccion(ctx context.Context, po int) (*types.ProductionOrder, error) { + pro := &types.ProductionOrder{} + // get production order + if err := s.db.Where("p_order_no=?", po).First(pro).Error; err != nil { + return nil, err + } + return pro, nil +} + +// OrdenesCliente implements Storager. +func (s *storage) OrdenesCliente(ctx context.Context, po int) ([]types.CustomerOrder, error) { + cos := []types.CustomerOrder{} + if err := s.db.Where("p_order_no=?", po).Order("c_order_no asc").Find(&cos).Error; err != nil { + return nil, err + } + return cos, nil +} + +// SalvarOrdenCliente implements Storager. +func (s *storage) SalvarOrdenCliente(ctx context.Context, co *types.CustomerOrder) error { + // save orden cliente + return s.db.Save(co).Error +} + +// SalvarOrdenProduccion implements Storager. +func (s *storage) SalvarOrdenProduccion(ctx context.Context, po *types.ProductionOrder) error { + // save orden produccion + return s.db.Save(po).Error +} + +func AutoMigrate(db *gorm.DB) error { + return db.AutoMigrate( + &types.Normas{}, + &types.ProductionOrder{}, + &types.CustomerOrder{}, + &types.Zebra{}, + &types.Paquete{}, + &types.Label{}, + ) +} + +func NewStorage(log logger.LoggerAdapter) (Storager, error) { + // create database connection + db, err := gorm.Open(sqlite.Open("db.sqlite"), &gorm.Config{}) + // auto migrate database + if err := AutoMigrate(db); err != nil { + return nil, err + } + return &storage{ + db: db, + mux: &sync.RWMutex{}, + log: log, + }, err +} diff --git a/internal/types/api.go b/internal/types/api.go new file mode 100644 index 0000000..cf14978 --- /dev/null +++ b/internal/types/api.go @@ -0,0 +1,189 @@ +package types + +type PEtiquetado uint8 + +const ( + Ata12 PEtiquetado = iota + 1 + Ata345 +) + +type Robot uint8 + +const ( + Robot12 Robot = iota + 1 + Robot345 +) + +type NroPaqueteActualReq struct { + PEtiquetado PEtiquetado + TimeStamp string +} + +type NroPaqueteActualRes struct { + NroMatricula string + TimeStamp string +} + +type NroPaqueteSiguienteReq struct { + PEtiquetado PEtiquetado + TimeStamp string +} + +type NroPaqueteSiguienteRes struct { + NroMatricula string + TimeStamp string +} + +type PaquetesReq struct { + Inicio string + Final string + TimeStamp string +} + +type PaquetesRes struct { + Paquetes []Paquete + TimeStamp string +} + +type PaqueteReq struct { + Codigo string + TimeStamp string +} + +type PaqueteRes struct { + Paquete *Paquete + TimeStamp string +} + +type EtiquetaReq struct { + Codigo string + TimeStamp string +} + +type EtiquetaRes struct { + Etiqueta *Label + TimeStamp string +} + +type EtiquetasReq struct { + TimeStamp string +} + +type EtiquetasRes struct { + Etiquetas []Label + TimeStamp string +} + +type SalvarEtiquetaReq struct { + Etiqueta *Label + TimeStamp string +} + +type SalvarEtiquetaRes struct { + Respuesta string + TimeStamp string +} + +type NormasReq struct { + Codigo string + TimeStamp string +} + +type NormasRes struct { + Normas *Normas + TimeStamp string +} + +type ImprimirPaqueteReq struct { + ImpresoraID string + Robot Robot + DatosEtiqueta *DatosEtiqueta + TimeStamp string +} + +type ImprimirPaqueteRes struct { + Respuesta string + TimeStamp string +} + +type OrdenProduccionReq struct { + PoID int + TimeStamp string +} + +type OrdenProduccionRes struct { + OrdenProduccion *ProductionOrder + TimeStamp string +} + +type OrdenClienteReq struct { + CoID int + TimeStamp string +} + +type OrdenClienteRes struct { + OrdenCliente *CustomerOrder + TimeStamp string +} + +type OrdenesClienteReq struct { + PoID int + TimeStamp string +} + +type OrdenesClienteRes struct { + OrdenesCliente []CustomerOrder + TimeStamp string +} + +type DatosEtiqueta struct { + CoID int + Peso float64 + PesoTeorico float64 + DesvioPeso float64 + Turno string + Operador string + Colada string + NrBarras string + NrEtiquetas string + NroMatricula string +} + +type OrdenesProduccionReq struct { + Limit int + TimeStamp string +} + +type OrdenesProduccionRes struct { + OrdenesProduccion []ProductionOrder + TimeStamp string +} + +type ImpresoraReq struct { + ID string + TimeStamp string +} + +type ImpresoraRes struct { + Impresora *Zebra + TimeStamp string +} + +type ImpresorasReq struct { + TimeStamp string +} + +type ImpresorasRes struct { + Impresoras []Zebra + TimeStamp string +} + +type SalvarImpresoraReq struct { + Impresora *Zebra + TimeStamp string +} + +type SalvarImpresoraRes struct { + Message string + TimeStamp string +} diff --git a/internal/types/co.go b/internal/types/co.go new file mode 100644 index 0000000..fd6f811 --- /dev/null +++ b/internal/types/co.go @@ -0,0 +1,94 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type CustomerOrder struct { + Inst string `json:"INST"` + DateTime string `json:"DATE_TIME"` + COrderNo int `json:"C_ORDER_NO" gorm:"primarykey"` + POrderNo int `json:"P_ORDER_NO" gorm:"index"` + SchedulNo int `json:"SCHEDUL_NO"` + OrdWeight string `json:"ORD_WEIGHT"` + OrdLen string `json:"ORD_LEN"` + OrLenTU string `json:"OR_LEN_T_U"` + OrLenTL string `json:"OR_LEN_T_L"` + PackType int `json:"PACK_TYPE"` + SectLayer int `json:"SECT_LAYER"` + LayerPack int `json:"LAYER_PACK"` + SecLastL int `json:"SEC_LAST_L"` + TotalSect int `json:"TOTAL_SECT"` + PackWidth int `json:"PACK_WIDTH"` + PackHigh int `json:"PACK_HIGH"` + OutpTolU int `json:"OUTP_TOL_U"` + OutpTolD int `json:"OUTP_TOL_D"` + LogoCode int `json:"LOGO_CODE"` + SecondLab string `json:"SECOND_LAB"` + PaintText string `json:"PAINT_TEXT"` + AddLabel1 string `json:"ADD_LABEL1"` + AddLabel2 string `json:"ADD_LABEL2"` + AddLabel3 string `json:"ADD_LABEL3"` + MaterCode string `json:"MATER_CODE"` + ProduDate int `json:"PRODU_DATE"` + LangLabel string `json:"LANG_LABEL"` + Warehouse string `json:"WAREHOUSE"` + Location string `json:"LOCATION"` + Marking string `json:"MARKING"` + DisForwar string `json:"DIS_FORWAR"` + NumTies int `json:"NUM_TIES"` + DisTies string `json:"DIS_TIES"` + DisMachin string `json:"DIS_MACHIN"` + Vbeln string `json:"VBELN"` + Posnr string `json:"POSNR"` + CoType string `json:"CO_TYPE"` + LoadBed int `json:"LOAD_BED"` + SecNum int `json:"SEC_NUM"` + Numpal int `json:"NUMPAL"` + Numbul string `json:"NUMBUL"` + Marfab int `json:"MARFAB"` + Sortb string `json:"SORTB"` + Strol1 int `json:"STROL1"` + Strol2 string `json:"STROL2"` + Strol3 int `json:"STROL3"` + Strol4 int `json:"STROL4"` + Strol5 int `json:"STROL5"` + Strol6 int `json:"STROL6"` + Strol7 int `json:"STROL7"` + Strol8 int `json:"STROL8"` + Strol9 int `json:"STROL9"` + Strol10 int `json:"STROL10"` + Strol11 int `json:"STROL11"` + Strol12 int `json:"STROL12"` + Strol13 int `json:"STROL13"` + Strol14 int `json:"STROL14"` + Strol15 int `json:"STROL15"` + Strol16 string `json:"STROL16"` + Strol17 string `json:"STROL17"` + Strol18 string `json:"STROL18"` + Strol19 string `json:"STROL19"` + Strol20 string `json:"STROL20"` + Strol21 string `json:"STROL21"` + Strol22 string `json:"STROL22"` + Strol23 string `json:"STROL23"` + Strol24 string `json:"STROL24"` + Strol25 string `json:"STROL25"` + Strol26 string `json:"STROL26"` + Strol27 string `json:"STROL27"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (c *CustomerOrder) BeforeCreate(tx *gorm.DB) (err error) { + c.CreatedAt = time.Now() + c.UpdatedAt = time.Now() + return +} + +func (c *CustomerOrder) BeforeUpdate(tx *gorm.DB) (err error) { + c.UpdatedAt = time.Now() + return +} diff --git a/internal/types/etiqueta.go b/internal/types/etiqueta.go new file mode 100644 index 0000000..2a66a43 --- /dev/null +++ b/internal/types/etiqueta.go @@ -0,0 +1,43 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type EtiquetaTipo uint8 + +const ( + EtiquetaEuropea EtiquetaTipo = iota + 1 + EtiquetaBritanica + EtiquetaAmericana +) + +var ( + TipoFormato = map[EtiquetaTipo]string{ + EtiquetaEuropea: "EU-200dpi", + EtiquetaAmericana: "US-200dpi", + EtiquetaBritanica: "UK-200dpi", + } +) + +type Label struct { + Codigo string `json:"codigo" gorm:"primaryKey"` + Tipo EtiquetaTipo + Contenido string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (l *Label) BeforeCreate(tx *gorm.DB) (err error) { + l.CreatedAt = time.Now() + l.UpdatedAt = time.Now() + return +} + +func (l *Label) BeforeUpdate(tx *gorm.DB) (err error) { + l.UpdatedAt = time.Now() + return +} diff --git a/internal/types/normas.go b/internal/types/normas.go new file mode 100644 index 0000000..c23ba66 --- /dev/null +++ b/internal/types/normas.go @@ -0,0 +1,36 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type Normas struct { + Codigo string `json:"codigo" gorm:"primarykey"` + Calidad string `json:"calidad"` + CodProducto string `json:"cod_producto,omitempty"` + CodMedida string `json:"cod_medida,omitempty"` + CodTolerancia string `json:"cod_tolerancia,omitempty"` + NormaProducto string `json:"norma_producto,omitempty"` + NormaMedida string `json:"norma_medida,omitempty"` + NormaTolerancia string `json:"norma_tolerancia,omitempty"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +type NormaList struct { + Lista []Normas `json:"Etiqueta"` +} + +func (n *Normas) BeforeCreate(tx *gorm.DB) (err error) { + n.CreatedAt = time.Now() + n.UpdatedAt = time.Now() + return +} + +func (n *Normas) BeforeUpdate(tx *gorm.DB) (err error) { + n.UpdatedAt = time.Now() + return +} diff --git a/internal/types/paquete.go b/internal/types/paquete.go new file mode 100644 index 0000000..8129d68 --- /dev/null +++ b/internal/types/paquete.go @@ -0,0 +1,38 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type Paquete struct { + NroPaquete string `gorm:"primarykey"` + OrdenProduccion int `gorm:"index"` + OrdenCliente int `gorm:"index"` + Producto string `gorm:"index"` + Colada string + Calidad string + Matnr string + Operador string + Turno string `gorm:"index"` + Longitud float64 + Barras uint8 + Peso float64 + PesoTeorico float64 + Normed string + Norpro string + Nortol string + DesvioPeso float64 + Confirmado bool + Procesado bool + Observaciones string + Reclasificado bool + CreatedAt time.Time `gorm:"index"` + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (Paquete) TableName() string { + return "paquetes" +} diff --git a/internal/types/po.go b/internal/types/po.go new file mode 100644 index 0000000..d6a16d2 --- /dev/null +++ b/internal/types/po.go @@ -0,0 +1,85 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type ProductionOrder struct { + Inst string `json:"INST"` + DateTime string `json:"DATE_TIME"` + POrderNo int `json:"P_ORDER_NO" gorm:"primarykey"` + SchedulNo int `json:"SCHEDUL_NO"` + SeqNumber int `json:"SEQ_NUMBER"` + PptimeWfc string `json:"PPTIME_WFC"` + PptimeMsc string `json:"PPTIME_MSC"` + SteelGrad string `json:"STEEL_GRAD"` + ITemp string `json:"I_TEMP"` + IHeight string `json:"I_HEIGHT"` + IWidth string `json:"I_WIDTH"` + ISection string `json:"I_SECTION"` + HeatingSt int `json:"HEATING_ST"` + FTarTemp string `json:"F_TAR_TEMP"` + FSection string `json:"F_SECTION"` + FSectType string `json:"F_SECT_TYPE"` + TotWeight string `json:"TOT_WEIGHT"` + TBeamBla int `json:"T_BEAM_BLA"` + TCustOrd int `json:"T_CUST_ORD"` + TestLen int `json:"TEST_LEN"` + PostFlag string `json:"POST_FLAG"` + ModuloX string `json:"MODULO_X"` + OvWTolU string `json:"OV_W_TOL_U"` + OvWTolL string `json:"OV_W_TOL_L"` + OvHTolU string `json:"OV_H_TOL_U"` + OvHTolL string `json:"OV_H_TOL_L"` + WeTTolU string `json:"WE_T_TOL_U"` + WeTTolL string `json:"WE_T_TOL_L"` + WeHTolU string `json:"WE_H_TOL_U"` + WeHTolL string `json:"WE_H_TOL_L"` + FlWDsU string `json:"FL_W_DS_U"` + FlWDsL string `json:"FL_W_DS_L"` + FlWOsU string `json:"FL_W_OS_U"` + FlWOsL string `json:"FL_W_OS_L"` + WeMetTU string `json:"WE_MET_T_U"` + WeMetTL string `json:"WE_MET_T_L"` + WeCenTol string `json:"WE_CEN_TOL"` + WeSquTol string `json:"WE_SQU_TOL"` + FlParTol string `json:"FL_PAR_TOL"` + BdRollID string `json:"BD_ROLL_ID"` + UrRollID string `json:"UR_ROLL_ID"` + EdRollID string `json:"ED_ROLL_ID"` + UfRollID string `json:"UF_ROLL_ID"` + SmRollID string `json:"SM_ROLL_ID"` + Grupo6 string `json:"GRUPO6"` + StName string `json:"ST_NAME"` + StWeighM string `json:"ST_WEIGH_M"` + StLen1 string `json:"ST_LEN_1"` + StLen2 string `json:"ST_LEN_2"` + StLen3 string `json:"ST_LEN_3"` + StLen4 string `json:"ST_LEN_4"` + StLen5 string `json:"ST_LEN_5"` + StLen6 string `json:"ST_LEN_6"` + StLen7 string `json:"ST_LEN_7"` + StLen8 string `json:"ST_LEN_8"` + StLen9 string `json:"ST_LEN_9"` + StLen10 string `json:"ST_LEN_10"` + StLen11 string `json:"ST_LEN_11"` + StLen12 string `json:"ST_LEN_12"` + Marfab int `json:"MARFAB"` + Sortb string `json:"SORTB"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (p *ProductionOrder) BeforeCreate(tx *gorm.DB) (err error) { + p.CreatedAt = time.Now() + p.UpdatedAt = time.Now() + return +} + +func (p *ProductionOrder) BeforeUpdate(tx *gorm.DB) (err error) { + p.UpdatedAt = time.Now() + return +} diff --git a/internal/types/ppack.go b/internal/types/ppack.go new file mode 100644 index 0000000..66140ae --- /dev/null +++ b/internal/types/ppack.go @@ -0,0 +1,54 @@ +package types + +type Ppack struct { + Grupo6 string `json:"grupo6"` + Po int `json:"po"` + Co int `json:"co"` + Colada string `json:"colada"` + Calidad string `json:"calidad"` + Matnr string `json:"matnr"` + Dibujo int `json:"dibujo"` + Operador string `json:"operador"` + Serie int `json:"serie"` + Nromatricula string `json:"nromatricula"` + NroBulto string `json:"nro_bulto"` + EtiquetaDoble string `json:"etiqueta_doble"` + Fecha int `json:"fecha"` + Turno string `json:"turno"` + Observacion1 string `json:"observacion1"` + Observacion2 string `json:"observacion2"` + Observacion3 string `json:"observacion3"` + PaqueteLongitud float64 `json:"paquete_longitud"` + PaqueteAncho int `json:"paquete_ancho"` + PaqueteAlto float64 `json:"paquete_alto"` + PaquetePeso int `json:"paquete_peso"` + PaqueteNroSecciones int `json:"paquete_nro_secciones"` + PaqueteNroMantos int `json:"paquete_nro_mantos"` + PaqueteNroSeccManto int `json:"paquete_nro_secc_manto"` + SeccionTipo string `json:"seccion_tipo"` + SeccionLongitud int `json:"seccion_longitud"` + SeccionAncho int `json:"seccion_ancho"` + SeccionAlto int `json:"seccion_alto"` + Idioma string `json:"idioma"` + Destino int `json:"destino"` + Hora int `json:"hora"` + Horario int `json:"horario"` + Inst string `json:"inst"` + Tren int `json:"tren"` + Normed string `json:"normed"` + Norpro string `json:"norpro"` + Nortol string `json:"nortol"` + Spras string `json:"spras"` + Statu int `json:"statu"` + Crlf string `json:"crlf"` + Maquina int `json:"maquina"` + Padre string `json:"padre"` + Paqpadre string `json:"paqpadre"` + RelevantTime string `json:"relevant_time"` + Desvio int `json:"desvio"` + Pesoteorico int `json:"pesoteorico"` + PesoteoricoReal int `json:"pesoteorico_real"` + DesvioTeoricoReal int `json:"desvio_teorico_real"` + FechaImpresion string `json:"fecha_impresion"` + PesoNivel1 int `json:"peso_nivel1"` +} diff --git a/internal/types/zebra.go b/internal/types/zebra.go new file mode 100644 index 0000000..d965ce4 --- /dev/null +++ b/internal/types/zebra.go @@ -0,0 +1,28 @@ +package types + +import ( + "time" + + "gorm.io/gorm" +) + +type Zebra struct { + ID string `gorm:"primarykey"` + Address string + Port int + Enabled bool + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +func (z *Zebra) BeforeCreate(tx *gorm.DB) (err error) { + z.CreatedAt = time.Now() + z.UpdatedAt = time.Now() + return +} + +func (z *Zebra) BeforeUpdate(tx *gorm.DB) (err error) { + z.UpdatedAt = time.Now() + return +}