17 Commits

Author SHA1 Message Date
arsalan
5144456721 fixes 2024-03-05 10:11:02 +05:30
arsalan
d475d3828b Add inventory 2024-03-01 18:12:17 +05:30
arsalan
f8263e8a35 add conf 2024-02-29 11:06:03 +05:30
arsalan
bd46d5ae52 fix prod api 2024-02-28 15:48:19 +05:30
arsalan
9633983dec fixes 2024-02-28 14:40:14 +05:30
arsalan
9a60105ed3 add vendor module 2024-02-21 17:22:45 +05:30
gowthaman.b
338f86a5f5 some updates 2024-02-09 14:49:25 +05:30
arsalan
fc94c7aacc delete api.log 2024-02-09 08:24:59 +00:00
arsalan
6ca803d7f2 fix updates 2024-02-09 13:04:38 +05:30
gowthaman.b
40933a2713 some updates 2024-02-08 17:50:08 +05:30
gowthaman.b
d8a4483c3c add shadow plaugin 2024-02-08 15:42:18 +05:30
gowthaman.b
db7bdffe33 add shadow plaugin 2024-02-08 15:38:36 +05:30
arsalan
4e069e0300 fixes 2024-02-08 13:01:03 +05:30
arsalan
b5c28dd288 add fixes 2024-01-24 17:40:20 +05:30
arsalan
3cd5c4c471 add excel templates fix apis 2024-01-24 10:01:25 +05:30
arsalan
2fecc4b3fd add excel import and export 2024-01-22 18:32:24 +05:30
arsalan
0b75681236 add filters, excel 2024-01-19 18:27:44 +05:30
39 changed files with 2198 additions and 285 deletions

7
.gitignore vendored
View File

@@ -44,3 +44,10 @@ application.yaml
initial-data.sql
app.yaml
*.env.json
### API Logs ###
api.log
api.2024*
### Excel FIles ###
./excel

BIN
Products_Template.xls Normal file

Binary file not shown.

253
api.http
View File

@@ -132,3 +132,256 @@ Authorization: {{auth-token}}
### delete a row
DELETE http://localhost:9001/api/vendor/product/2
Authorization: {{auth-token}}
### create vendor
POST http://localhost:9001/api/vendor/
Content-Type: application/json
Authorization: {{auth-token}}
{
"name": "arsalan",
"msme": "1234",
"gstNumber": "GST123",
"address": "Bangalore",
"rating": 2,
"contacts": [
{
"name": "contact1",
"email": "abc@cyz.com",
"mobile": "01234567890"
}
]
}
### create batch vendor
POST http://localhost:9001/api/vendor/batch
Content-Type: application/json
Authorization: {{auth-token}}
[
{
"name": "john",
"description": "5678",
"hsnCode": "5678",
"gstNumber": "GST567",
"address": "Mumbai",
"rating": 4,
"contacts": [
{
"name": "contact1",
"email": "xyz@abc.com",
"phone": "9876543210"
}
]
},
{
"name": "emma",
"description": "7890",
"hsnCode": "7890",
"gstNumber": "GST789",
"address": "Delhi",
"rating": 3,
"contacts": [
{
"name": "contact2",
"email": "def@uvw.com",
"phone": "8765432109"
}
]
},
{
"name": "alex",
"description": "2345",
"hsnCode": "2345",
"gstNumber": "GST234",
"address": "Chennai",
"rating": 5,
"contacts": [
{
"name": "contact3",
"email": "ghi@rst.com",
"phone": "7654321098"
}
]
}
]
### GET ALL VENDORS
POST http://localhost:9001/api/vendor/getAll
Content-Type: application/json
Authorization: {{auth-token}}
{
"common": {
"sortAsc": true
},
"vendorFilters": {
"nameLike": "a"
}
}
### create batch pos
POST http://localhost:9001/api/vendor/po/batch
Content-Type: application/json
Authorization: {{auth-token}}
[
{
"products": [
{
"productId": "1232",
"productName": "chair",
"unitPrice": 34.2,
"quantity": 10,
"description": "wooden chair"
}
],
"referenceQuotation": "12323",
"totalAmount": 342,
"poNum": "1",
"poDate": "2024-01-10",
"validTill": "2024-02-10",
"tnc": ["tnc1", "tnc2"]
},
{
"products": [
{
"productId": "5678",
"productName": "table",
"unitPrice": 45.5,
"quantity": 5,
"description": "glass table"
}
],
"referenceQuotation": "56789",
"totalAmount": 227.5,
"poNum": "2",
"poDate": "2024-10-25",
"validTill": "2024-10-25",
"tnc": ["tnc3", "tnc4"]
},
{
"products": [
{
"productId": "91011",
"productName": "lamp",
"unitPrice": 15.75,
"quantity": 20,
"description": "floor lamp"
}
],
"referenceQuotation": "9101112",
"totalAmount": 315,
"poNum": "3",
"poDate": "2024-10-25",
"validTill": "2024-12-25",
"tnc": ["tnc5", "tnc6"]
}
]
### GET ALL POS
POST http://localhost:9001/api/vendor/po/getAll
Content-Type: application/json
Authorization: {{auth-token}}
{
"common" : {},
"poFilters": {}
}
### CREATE QUOTES
POST http://localhost:9001/api/vendor/quote/batch
Content-Type: application/json
Authorization: {{auth-token}}
[
{
"products": [
{
"productId": "1232",
"productName": "chair",
"unitPrice": 34.2,
"quantity": 10,
"description": "wooden chair"
}
],
"reqForQuoteNum": "12323",
"totalAmount": 342,
"quoteNum": "1",
"quoteDate": "2024-10-24",
"validTill": "2024-11-24",
"tnc": ["tnc1", "tnc2"]
},
{
"products": [
{
"productId": "5678",
"productName": "table",
"unitPrice": 45.5,
"quantity": 5,
"description": "glass table"
}
],
"reqForQuoteNum": "56789",
"totalAmount": 227.5,
"quoteNum": "2",
"quoteDate": "2024-10-25",
"validTill": "2024-11-25",
"tnc": ["tnc3", "tnc4"]
},
{
"products": [
{
"productId": "91011",
"productName": "lamp",
"unitPrice": 15.75,
"quantity": 20,
"description": "floor lamp"
}
],
"reqForQuoteNum": "9101112",
"totalAmount": 315,
"quoteNum": "3",
"quoteDate": "2024-10-25",
"validTill": "2024-12-25",
"tnc": ["tnc5", "tnc6"]
}
]
### GET ALL QUOTES
POST http://localhost:9001/api/vendor/quote/getAll
Content-Type: application/json
Authorization: {{auth-token}}
{
"common" : {},
"quoteFilters": {}
}
### GET ALL PRODUCTS
POST http://localhost:9001/api/vendor/product/getAll
Content-Type: application/json
Authorization: {{auth-token}}
{
"common" : {},
"quoteFilters": {}
}
### GET NEXT PO SEQ NUMBER
GET http://localhost:9001/api/vendor/po/next
Content-Type: application/json
Authorization: {{auth-token}}
### GET NEXT QUOTE SEW NUMBER
GET http://localhost:9001/api/vendor/quote/next
Content-Type: application/json
Authorization: {{auth-token}}
### GET NEXT INCOMING SEW NUMBER
GET http://localhost:9001/api/vendor/incoming/next
Content-Type: application/json
Authorization: {{auth-token}}

61
app_conf.yaml Normal file
View File

@@ -0,0 +1,61 @@
#DO Not edit this file, copy to your HOME Directory and then rename it to app.yaml and then edit it
app:
db:
pass: password
url: jdbc:postgresql://10.10.10.211/arsalan_rmc_module_app
user: arsalan
name: arsalan_rmc_module_app
run_migration: 'true'
cors:
enabled: 'true'
hosts: www.readymixerp.com,app.readymixerp.com
port: '9001'
cache:
redis_uri: redis://10.10.10.112:6379/
iam:
url: https://auth.readymixerp.com
realm: rmc-dev
client_redirect_uri: http://localhost:9001/auth/code
client: rmc
scripts:
path: /Users/gowthaman.b/IdeaProjects/rmc_modules_api/src/main/resources/scripts
security:
private_key: |-
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD4ba8OhlyB9MUx
MFmT8c9sOKqXOG6ZM6qLxr5SnY1au47rYsHXt8Hb+tTUxpkf+5bndaZYGVgQ1mtw
eEVj3qZq9A+FnxxwZ9uIIdbOUPvsZLzNYnK3bFFRsmWMf30gDs6ZdS63b2tnXXE0
aoItwVguElUKVXKUymS0VlBB0ZLCYTlD6Q4sDm7HGXJZj5kVNVbBCBe42yLx8Y1F
TyNL8nPSS+SAdLUaPJ/6j+741+exAIOc0rSBJOMF0XNOwBZ85EuOiPa0e1sUz0qj
VfmZyeRFxkSWJBnqum1jrVFp55bMb37DYtZa0aFIcPdDfY42frDlPLcI4zzRwCn3
ggHL/nL9AgMBAAECggEAJ85sxu8zl8/l4EsG3M8EdVWidrGgUyRgDElFCiLcWVta
prqVJIt5YNYRJU5J5Jc2fRGxHPEOrJVW84IUsvskVQM/ZiHyd3ZvdaGKdFZYpO5t
VvGSlR53l0IhGxal24L+isCn7X+ec5pu6b8JQJX4RbBConHCTDdz/yDMzQcXiiqj
ezzSovZ1Xy/2dn7sOTFtEZi47d3AhBnjh8Xqk3Dc9UChooxuIU6WEbqWFxEkbzJS
sXIv9xADVDqFqjHGv6Tk1W+y7y8M2EHosJfhO0LmWFL7nUdw0WSJV+UqQxHrUSJs
SnYHkKRTYl2ljpjkuECp/YqUqdlNq/5T5jBE6cyopwKBgQD6+XGZfssdAqfnaEK2
nHdUAdklUFAFQpSmwIUwTZEHDC/CD+ErVjfbEfZ2mFOvWAIMwLmiLFuDT7E5sHaT
K4A2DQ8KyU3iJkH4nhxdYepLc7MSYElkn6fHNrXcJ9vPACmrtoa9rVW/LpAjsRq6
fDxLo12/+EmFvpZ0oEAIQXk6ZwKBgQD9ZzBgPapI8m7cjcdojqq0dJ2M5Sw7Bx5n
VFOC3H4Cx0xWTdwwZ9CZQ4v/XiiHiUGzwhfkNJ2x3DdpUCkPDD8o3cFXPRW4GsjD
kv/D0kL/JJAesG9XB9yMTMBoe2yGMudDVc7SYgUI2YXhmHYkpcjSzM0DftLL2Z47
GY1h385Q+wKBgGTRxe/Kfp+lzHtqZ7ph+pG1uFyD+dFTINIn7pkr38G8BIdpx6OY
HBIWEjMsGBoNOa2T0j6yoQSMA/7Pw6J1TCjqcAt+OJpLkh7krTJaPjuXO+163qDc
fhLKCJ5rKKLsRtEjHtedhR+q/d5IrBsUA0jDVMrkW+ytVlV9dpuaaa+rAoGASON8
m8JBD/iEAPbbK+0VlxCQHO3ymgwDJ8+usc6AhIYVJCIDOv0xmFRAmbTYzZuihXVH
8AFedsGUQrunA8gPBs86hMByVeGGbBMFdKsvUDqRJfK0JAGD4+tT0PnnjnZn5Qty
kTtWnWQMSYbUPNhe+pukQOQi+DXheLhx3XxF2S8CgYEAopLjGIR/xeuV7QkGJfCO
d2wEJROBPd3pbDlR4fLDO8RCw3irFYQgQd9WgGJY5KgyfjKLHkK7DMQKn+/yfUp5
UKeesBDXATpyQQrpfoKIhhZKtYphOwvIzugtLsd5sza++sjC9RwkRmYr0rzlHdUl
vtr3fru0Bzven2MeiQnqmCM=
-----END PRIVATE KEY-----
public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+G2vDoZcgfTFMTBZk/HP
bDiqlzhumTOqi8a+Up2NWruO62LB17fB2/rU1MaZH/uW53WmWBlYENZrcHhFY96m
avQPhZ8ccGfbiCHWzlD77GS8zWJyt2xRUbJljH99IA7OmXUut29rZ11xNGqCLcFY
LhJVClVylMpktFZQQdGSwmE5Q+kOLA5uxxlyWY+ZFTVWwQgXuNsi8fGNRU8jS/Jz
0kvkgHS1Gjyf+o/u+NfnsQCDnNK0gSTjBdFzTsAWfORLjoj2tHtbFM9Ko1X5mcnk
RcZEliQZ6rptY61RaeeWzG9+w2LWWtGhSHD3Q32ONn6w5Ty3COM80cAp94IBy/5y
/QIDAQAB
-----END PUBLIC KEY-----

View File

@@ -1,8 +1,11 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
kotlin("jvm") version "1.9.22"
kotlin("kapt") version "1.9.22"
id("idea")
id("io.ebean") version "13.23.2"
id("com.github.johnrengelman.shadow") version "8.1.1"
application
}
@@ -38,6 +41,8 @@ dependencies {
implementation("org.apache.httpcomponents:httpclient:4.5.14")
implementation("org.apache.poi:poi:5.0.0")
implementation("org.apache.poi:poi-ooxml:5.0.0")
implementation("com.google.code.gson:gson:2.8.8")
api ("net.cactusthorn.config:config-core:0.81")
api ("net.cactusthorn.config:config-yaml:0.81")
kapt("net.cactusthorn.config:config-compiler:0.81")
@@ -52,6 +57,18 @@ kotlin {
jvmToolchain(17)
}
tasks {
named<ShadowJar>("shadowJar") {
archiveBaseName.set("rest-api")
mergeServiceFiles()
manifest {
attributes(mapOf("Main-Class" to "com.restapi.MainKt"))
}
isZip64 = true
}
}
application {
mainClass.set("com.restapi.MainKt")
}

BIN
excel/IncomingInventory.xls Normal file

Binary file not shown.

BIN
excel/OutgoingInventory.xls Normal file

Binary file not shown.

BIN
excel/Pos.xls Normal file

Binary file not shown.

BIN
excel/Products.xls Normal file

Binary file not shown.

BIN
excel/Quotes.xls Normal file

Binary file not shown.

BIN
excel/VendorList.xls Normal file

Binary file not shown.

View File

@@ -42,7 +42,7 @@ class AppAccessManager : AccessManager {
Role.DbOps -> listOf("ROLE_DB_OPS")
Role.Entity -> loadEntityActionRole(entity, action)
is Role.Standard -> role.action.toList().map { "ROLE_${entity}_${it}" }
is Role.Explicit -> role.roles
is Role.Explicit -> role.roles.toList() + listOf("ROLE_ADMIN")
}.map(String::uppercase)
}

View File

@@ -6,8 +6,6 @@ import com.restapi.config.AppConfig.Companion.appConfig
import com.restapi.config.Auth.validateAuthToken
import com.restapi.controllers.*
import com.restapi.domain.DataNotFoundException
import com.restapi.domain.Product
import com.restapi.domain.Session
import com.restapi.domain.Session.currentTenant
import com.restapi.domain.Session.currentUser
import com.restapi.domain.Session.objectMapper
@@ -114,46 +112,125 @@ fun main(args: Array<String>) {
path("/vendor") {
path("/") {
post("", Vendor::create, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE", "ROLE_ADMIN"))))
get("", Vendor::get, Roles(Role.Explicit(listOf("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE", "ROLE_ADMIN"))))
get("quotes/{id}", Vendor::getQuotes, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW"))))
get("pos/{id}", Vendor::getPos, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_VIEW", "ROLE_PO_CREATE`"))))
put("/rate/{id}/{rating}", Vendor::rate, Roles(Role.Explicit(listOf("ROLE_VENDOR_CREATE"))))
post("", VendorCtrl::create, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
post("/batch", VendorCtrl::createBatch, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
get("/{id}", VendorCtrl::get, Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE")))
post(
"/getAll",
VendorCtrl::getAll,
Roles(Role.Explicit("ROLE_VENDOR_VIEW", "ROLE_VENDOR_CREATE"))
)
get(
"quotes/{id}",
VendorCtrl::getQuotes,
Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE", "ROLE_VENDOR_VIEW"))
)
get("pos/{id}", VendorCtrl::getPos, Roles(Role.Explicit("ROLE_PO_VIEW", "ROLE_PO_CREATE`")))
put("/rate/{id}/{rating}", VendorCtrl::rate, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
put("/{id}", VendorCtrl::update, Roles(Role.Explicit("ROLE_VENDOR_CREATE")))
}
path("/incoming") {
post("", IncomingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get("/next", IncomingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get(
"/{id}",
IncomingInventoryCtrl::get,
Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
)
put("/{id}", IncomingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
post(
"/getAll",
IncomingInventoryCtrl::getAll,
Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
)
}
path("/outgoing") {
post("", OutgoingInventoryCtrl::create, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get("/next", OutgoingInventoryCtrl::getNextNum, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
get(
"/{id}",
OutgoingInventoryCtrl::get,
Roles(Role.Explicit("ROLE_INVENTORY_VIEW", "ROLE_INVENTORY_CREATE"))
)
put("/{id}", OutgoingInventoryCtrl::update, Roles(Role.Explicit("ROLE_INVENTORY_CREATE")))
post(
"/getAll",
OutgoingInventoryCtrl::getAll,
Roles(Role.Explicit("ROLE_INVENTORY_CREATE", "ROLE_INVENTORY_VIEW"))
)
}
path("/po") {
post("", PurchaseOrder::create, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_ADMIN"))))
get("/{id}", PurchaseOrder::get, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE"))))
put("/approve/{id}", PurchaseOrder::approve, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_APPROVE"))))
put("/reject/{id}", PurchaseOrder::reject, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_APPROVE"))))
get("/refQuote/{id}", PurchaseOrder::quoteReference, Roles(Role.Explicit(listOf("ROLE_PO_CREATE", "ROLE_PO_VIEW"))))
get("/next", PurchaseOrderCtrl::getNextNum, Roles(Role.Explicit("ROLE_PO_CREATE")))
post("", PurchaseOrderCtrl::create, Roles(Role.Explicit("ROLE_PO_CREATE")))
post("/batch", PurchaseOrderCtrl::createBatch, Roles(Role.Explicit("ROLE_PO_CREATE")))
post(
"/getAll",
PurchaseOrderCtrl::getAll,
Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_VENDOR_CREATE"))
)
get(
"/{id}",
PurchaseOrderCtrl::get,
Roles(Role.Explicit("ROLE_PO_CREATE", "ROLE_PO_VIEW", "ROLE_QUOTE_CREATE"))
)
put("/{id}", PurchaseOrderCtrl::update, Roles(Role.Explicit("ROLE_PO_CREATE")))
put("/approve/{id}", PurchaseOrderCtrl::approve, Roles(Role.Explicit()))
put("/reject/{id}", PurchaseOrderCtrl::reject, Roles(Role.Explicit()))
get("/refQuote/{id}", PurchaseOrderCtrl::quoteReference, Roles(Role.Explicit("ROLE_PO_CREATE")))
}
path("/quote") {
post("", Quotation::create, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN"))))
get("/{id}", Quotation::get, Roles(Role.Explicit(listOf("ROLE_QUOTE_VIEW", "ROLE_ADMIN", "ROLE_PO_CREATE", "ROLE_QUOTE_CREATE"))))
get("/po/{id}", Quotation::generatePO, Roles(Role.Explicit(listOf("ROLE_ADMIN", "ROLE_PO_CRETE"))))
get("/rfq/{rfqNum}", Quotation::reqForQuote, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))))
delete("/{id}", Quotation::delete, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN"))))
get("/next", QuotationCtrl::getNextNum, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
post("", QuotationCtrl::create, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
post("/batch", QuotationCtrl::createBatch, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
post(
"/getAll",
QuotationCtrl::getAll,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_QUOTE_VIEW"))
)
get("/{id}", QuotationCtrl::get, Roles(Role.Explicit("ROLE_QUOTE_VIEW", "ROLE_QUOTE_CREATE")))
put("/{id}", QuotationCtrl::update, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
delete("/{id}", QuotationCtrl::delete, Roles(Role.Explicit("ROLE_QUOTE_CREATE")))
}
path("/product") {
post("", ProductCtrl::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN"))))
//get("/{hsnCode}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
put("/{id}", ProductCtrl::update, Roles(Role.Explicit(listOf("ROLE_PRODUCT_UPDATE", "ROLE_ADMIN"))))
//patch("/{id}", ProductCtrl::patch, Roles(Role.Explicit(listOf("ROLE_PRODUCT_UPDATE", "ROLE_ADMIN"))))
delete("/{id}", ProductCtrl::delete, Roles(Role.Explicit(listOf("ROLE_PRODUCT_DELETE", "ROLE_ADMIN"))))
get("", ProductCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
post("", ProductCtrl::create, Roles(Role.Explicit("ROLE_PRODUCT_CREATE")))
put("/{id}", ProductCtrl::update, Roles(Role.Explicit("ROLE_PRODUCT_CREATE")))
delete("/{id}", ProductCtrl::delete, Roles(Role.Explicit("ROLE_PRODUCT_CREATE")))
patch("/{id}", ProductCtrl::patch, Roles(Role.Explicit("ROLE_PRODUCT_CREATE")))
post("/getAll", ProductCtrl::getAll, Roles(Role.Explicit("ROLE_PRODUCT_VIEW")))
get("/{id}", ProductCtrl::get, Roles(Role.Explicit("ROLE_PRODUCT_VIEW")))
}
path("/doc") {
post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN"))))
post("", DocumentCtrl::create, Roles(Role.Explicit("ROLE_DOC_CREATE")))
//why type and refid are clubbed ??
get("/{type}/{refId}", Document::getWithRefId, Roles(Role.Explicit(listOf("ROLE_DOC_VIEW", "ROLE_ADMIN", "ROLE_PRODUCT_CREATE"))))
get("/{id}", Document::get, Roles(Role.Explicit(listOf("ROLE_DOC_VIEW", "ROLE_ADMIN", "ROLE_PRODUCT_CREATE"))))
get("/print/{id}", Document::print, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_DOC_VIEW"))))
delete("/{id}", Document::delete, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE"))))
get(
"/{type}/{refId}",
DocumentCtrl::getWithRefId,
Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE"))
)
get("/{id}", DocumentCtrl::get, Roles(Role.Explicit("ROLE_DOC_VIEW", "ROLE_PRODUCT_CREATE")))
get(
"/print/{id}",
DocumentCtrl::print,
Roles(Role.Explicit("ROLE_DOC_CREATE", "ROLE_DOC_VIEW"))
)
delete("/{id}", DocumentCtrl::delete, Roles(Role.Explicit("ROLE_DOC_CREATE")))
}
path("/reqForQuote") {
post("", RequestForQuote::create, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE"))))
get("/{id}", RequestForQuote::get, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW"))))
put("/{id}", RequestForQuote::update, Roles(Role.Explicit(listOf("ROLE_RFQ_CREATE"))))
post(
"",
RequestForQuote::create,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
)
get(
"/{id}",
RequestForQuote::get,
Roles(Role.Explicit("ROLE_RFQ_CREATE", "ROLE_RFQ_VIEW", "ROLE_QUOTE_VIEW", "ROLE_PO_VIEW"))
)
put(
"/{id}",
RequestForQuote::update,
Roles(Role.Explicit("ROLE_QUOTE_CREATE", "ROLE_PO_CREATE", "ROLE_RFQ_CREATE"))
)
}
}
post("/script/database/{name}", Entities::executeStoredProcedure, Roles(adminRole, Role.DbOps))

View File

@@ -0,0 +1,74 @@
package com.restapi
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.restapi.controllers.QueryParam
import com.restapi.controllers.RawQuery
class FDeserializer : JsonDeserializer<F>() {
override fun deserialize(p: JsonParser, p1: DeserializationContext?): F {
//custom logic to do thia
val node = p.readValueAsTree<JsonNode>()
if (node.isObject) {
if (node.has("name")) {
return F.P(name = node.get("name").textValue())
} else if (node.has("num")) {
return F.Q(num = node.get("num").textValue())
} else if (node.has("tag")) {
return F.D(tag = node.get("tag").textValue())
}
} else {
//incorrect
}
throw IllegalArgumentException()
}
}
val om = jacksonObjectMapper()
@JsonDeserialize(using = FDeserializer::class)
sealed interface F {
data class P(val name: String) : F
data class Q(val num: String) : F
data class D(val tag: String) : F
}
val j = """
{"name":"a"}
""".trimIndent()
val j2 = """
{"num":"a"}
""".trimIndent()
val j3 = """
{"tag":"a"}
""".trimIndent()
val j4 = """
{
"sql":"aaaa",
"params": {
"a":"b",
"c": {
"type":"STRING",
"value":"aaaa"
}
}
}
""".trimIndent()
fun main() {
println(om.readValue<F>(j))
println(om.readValue<F>(j2))
println(om.readValue<F>(j3))
println(om.readValue<RawQuery>(j4))
}

View File

@@ -235,7 +235,7 @@ enum class Action {
sealed class Role {
open class Standard(vararg val action: Action) : Role()
data object Entity : Role()
data class Explicit(val roles: List<String>) : Role()
open class Explicit(vararg val roles: String) : Role()
data object DbOps : Role()
}

View File

@@ -6,18 +6,15 @@ import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.restapi.domain.*
import com.restapi.domain.Product
import com.restapi.domain.PurchaseOrder
import com.restapi.domain.Quotation
import com.restapi.domain.Session.currentUser
import com.restapi.domain.Session.database
import com.restapi.domain.Session.findDataModelByEntityAndUniqId
import com.restapi.domain.Vendor
import com.restapi.integ.Scripting
import io.ebean.CallableSql
import io.ebean.RawSqlBuilder
import io.javalin.http.*
import org.slf4j.LoggerFactory
import java.io.FileInputStream
import java.sql.Types
import java.time.LocalDate
import java.time.LocalDateTime
@@ -374,33 +371,89 @@ object Entities {
}
}
object PurchaseOrder {
data class Filters(val common: CommonFilters, val custom: CustomFilters)
data class SequenceNumber(val number: String)
data class BatchPos(val pos: List<PurchaseOrder>)
object PurchaseOrderCtrl {
fun getNextNum(ctx: Context) {
val prefix = "PO/"
val cnt = database.find(PurchaseOrder::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
fun get(ctx: Context) {
val id = ctx.pathParam("id")
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id")
ctx.json(po)
ctx.json(po).status(HttpStatus.OK)
}
data class PF(val common: CommonFilters, val poFilters: POFilters)
fun getAll(ctx: Context) {
val filters = ctx.bodyAsClass<PF>()
val pos = searchPos(filters.common, filters.poFilters)
val excel = ctx.queryParam("excel")
if (excel != null) {
exportPos(pos)
val inputStream = FileInputStream("./excel/Pos.xls")
ctx.result(inputStream).status(HttpStatus.OK)
} else {
ctx.json(pos).status(HttpStatus.OK)
}
}
fun create(ctx: Context) {
val po = ctx.bodyAsClass<PurchaseOrder>()
database.save(po)
ctx.result("po created")
val prods = po.products
if (prods.isEmpty()) {
ctx.json(mapOf("error" to "empty product list")).status(HttpStatus.BAD_REQUEST)
return
}
database.save(po)
ctx.json(po).status(HttpStatus.CREATED)
}
fun createBatch(ctx: Context) {
val pos = ctx.bodyAsClass<List<PurchaseOrder>>()
val txn = database.beginTransaction()
try {
txn.isBatchMode = true
for (po in pos) database.save(po)
txn.commit()
ctx.status(HttpStatus.CREATED).result("POS Created")
} catch (e: Exception) {
txn.rollback()
ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Pos Creation failed" + e.message)
} finally {
txn.end()
}
ctx.result("pos batch created").status(HttpStatus.CREATED)
}
fun approve(ctx: Context) {
val id = ctx.pathParam("id")
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id")
po.approvalStatus = ApprovalStatus.APPROVED
po.save()
ctx.result("po with id $id approved")
ctx.json(po).status(HttpStatus.CREATED)
//reject all other pos pertaining to the same tx ??
}
fun reject(ctx: Context) {
val id = ctx.pathParam("id")
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id")
po.approvalStatus = ApprovalStatus.REJECTED
po.save()
ctx.result("po with id $id rejected")
po.apply {
approvalStatus = ApprovalStatus.REJECTED
save()
}
ctx.json(po).status(HttpStatus.CREATED)
}
fun quoteReference(ctx: Context) {
//gets the quote reference on which this po is based on
val id = ctx.pathParam("id")
@@ -410,6 +463,22 @@ object PurchaseOrder {
?: throw NotFoundResponse("reference quotation not found for po $id")
ctx.json(quote)
}
fun update(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("po not found for $id")
val updatedPo = ctx.bodyAsClass<PurchaseOrder>()
po.patchValues(updatedPo)
po.update()
ctx.json(po).status(HttpStatus.OK)
}
fun delete(ctx: Context) {
val id = ctx.pathParam("id")
val po = database.find(PurchaseOrder::class.java, id) ?: throw NotFoundResponse("no po found with id $id")
database.delete(po)
ctx.status(HttpStatus.OK)
}
}
data class ProductSearch(
@@ -419,175 +488,419 @@ data class ProductSearch(
object ProductCtrl {
fun get(ctx: Context) {
val hsnCode = ctx.pathParam("hsnCode")
val product = database.find(Product::class.java, hsnCode) ?: throw NotFoundResponse("Product not found for $hsnCode")
ctx.json(product)
val id = ctx.pathParam("id")
val product = database.find(Product::class.java)
.where()
.eq("sys_pk", id.toLong())
.findOne()
?: throw NotFoundResponse("Product not found for $id")
ctx.json(product).status(HttpStatus.OK)
}
data class PF(val common: CommonFilters, val productFilters: ProductFilters)
fun getAll(ctx: Context) {
val productList = Session.database.find(Product::class.java)
.findList()
.sortedBy { it.hsnCode }
val filters = ctx.bodyAsClass<PF>()
val prods = searchProducts(filters.common, filters.productFilters)
val excel = ctx.queryParam("excel")
if (excel != null) {
exportProds(prods)
val inputStream = FileInputStream("./excel/Products.xls")
ctx.result(inputStream).status(HttpStatus.OK)
ctx.json(productList)
} else {
ctx.json(prods).status(HttpStatus.OK)
}
}
fun create(ctx: Context) {
val product = ctx.bodyAsClass<Product>()
database.save(product)
ctx.json(product).status(HttpStatus.CREATED)
}
fun delete(ctx: Context) {
val id = ctx.pathParam("id")
val product = database.delete(Product::class.java, id)
val prod = database.find(Product::class.java, id) ?: throw NotFoundResponse("no product found with id $id")
database.delete(prod)
ctx.status(HttpStatus.OK)
}
fun patch(ctx: Context) {
val id = ctx.pathParam("id")
val patchValues = ctx.bodyAsClass<Map<String, Any>>()
database.beginTransaction().use {
patchValues.entries.forEach { en ->
val key = en.key
val value = en.value
database.sqlUpdate("update products set $key = ? where id = ?").apply {
setParameter(1, value)
setParameter(2, id)
execute()
}
}
it.commit()
}
}
fun update(ctx: Context) {
val id = ctx.pathParam("id")
val id = ctx.pathParam("id").toLong()
val product = database.find(Product::class.java, id) ?: throw NotFoundResponse("product not found for $id")
val updatedProduct = ctx.bodyAsClass<Product>()
product.patchValues(updatedProduct)
product.update()
ctx.json(product).status(HttpStatus.OK)
}
@JvmStatic
fun main(args: Array<String>) {
val patchValues = mapOf("name" to 1)
val id = 1;
database.beginTransaction().use {
patchValues.entries.forEach { en ->
val key = en.key
val value = en.value
database.sqlUpdate("update product set $key = ? where sys_pk = ?").apply {
setParameter(1, value)
setParameter(2, id)
execute()
}
}
it.commit()
}
}
object Quotation {
}
object QuotationCtrl {
fun getNextNum(ctx: Context) {
val prefix = "QUOTE/"
val cnt = database.find(Quotation::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
fun get(ctx: Context) {
val id = ctx.pathParam("id")
val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id")
ctx.status(HttpStatus.OK)
ctx.json(quote)
}
data class QF(val common: CommonFilters, val quoteFilters: QuoteFilters)
fun getAll(ctx: Context) {
val filters = ctx.bodyAsClass<QF>()
val excel: String? = ctx.queryParam("excel")
val quotes = searchQuotes(filters.common, filters.quoteFilters)
if (excel != null) {
exportQuotations(quotes)
val inputStream = FileInputStream("./excel/Quotes.xls")
ctx.result(inputStream).status(HttpStatus.OK)
} else {
ctx.json(quotes).status(HttpStatus.OK)
}
}
fun create(ctx: Context) {
val quote = ctx.bodyAsClass<Quotation>()
//we have to check if the quotation created date is below the expiry of rfq
val rfq = database.find(com.restapi.domain.ReqForQuote::class.java)
.where()
.eq("reqForQuoteNum", quote.reqForQuoteNum)
.findOne()
if(rfq != null){
//compare dates
if(quote.quoteDate!! <= rfq.openTill) {
//valid
database.save(quote)
ctx.result("quote created")
}else {
ctx.result("request for quote closed")
//validation
val prods = quote.products
if (prods.isEmpty()) {
ctx.json(mapOf("error" to "empty product list")).status(HttpStatus.BAD_REQUEST)
return
}
}else {
throw NotFoundResponse("request for quote not found for this quotation")
database.save(quote)
ctx.json(quote).status(HttpStatus.CREATED)
}
fun createBatch(ctx: Context) {
val quotes = ctx.bodyAsClass<List<Quotation>>()
val txn = database.beginTransaction()
try {
txn.isBatchMode = true
for (quote in quotes) database.save(quote)
txn.commit()
ctx.status(HttpStatus.CREATED).result("Quotes Created")
} catch (e: Exception) {
txn.rollback()
ctx.status(HttpStatus.INTERNAL_SERVER_ERROR).result("Quotes Creation failed" + e.message)
} finally {
txn.end()
}
ctx.result("Quotes batch created").status(HttpStatus.CREATED)
}
fun delete(ctx: Context) {
val id = ctx.pathParam("id")
val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for id $id")
quote.delete()
ctx.result("quote with $id deleted")
val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("no quote found with id $id")
database.delete(quote)
ctx.status(HttpStatus.OK)
}
fun generatePO(ctx :Context){
//user should be redirected to a po form submission with prefilled values
//create a PO object with values from the quote and then send it as body to vendor/po/create ??
}
fun reqForQuote(ctx :Context){
val reqForQuoteNum = ctx.pathParam(("rfqNum"))
val rfq = database.find(RequestForQuote::class.java)
.where()
.eq("reqForQuoteNum", reqForQuoteNum)
?: throw NotFoundResponse("request for quote not found for this quotation")
ctx.json(rfq)
fun update(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val quote = database.find(Quotation::class.java, id) ?: throw NotFoundResponse("quote not found for $id")
val updatedQuote = ctx.bodyAsClass<Quotation>()
quote.patchValues(updatedQuote)
quote.update()
ctx.json(quote).status(HttpStatus.OK)
}
}
object Document {
object DocumentCtrl {
fun get(ctx: Context) {
val id = ctx.pathParam("id")
val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no doc found with id $id")
ctx.status(HttpStatus.OK)
ctx.json(doc)
}
fun create(ctx: Context) {
val doc = ctx.bodyAsClass<Document>()
database.save(doc)
ctx.result("doc created")
ctx.status(HttpStatus.CREATED)
ctx.json(doc)
}
fun print(ctx: Context) {
//would be handled in the frontend ??
}
fun delete(ctx: Context) {
val id = ctx.pathParam("id")
val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no doc found with id $id")
//doc.delete()
ctx.result("document deleted")
val doc = database.find(Document::class.java, id) ?: throw NotFoundResponse("no document found with id $id")
database.delete(doc)
ctx.status(HttpStatus.OK)
}
fun getWithRefId(ctx: Context) {
//fetches a particular doc (po, quote) with ref id
val refId = ctx.pathParam("refId")
val doc = database.find(Document::class.java)
.where()
.eq("refId", refId)
.eq("typeOfDoc", DocType.valueOf(ctx.pathParam("type")))
.eq("refIdOfDoc", refId)
?: throw NotFoundResponse("no doc found for refId $refId")
ctx.status(HttpStatus.OK)
ctx.json(doc)
}
}
object Vendor {
object VendorCtrl {
val logger = LoggerFactory.getLogger("Vendor")
fun get(ctx: Context) {
val id = ctx.pathParam("id")
val id = ctx.pathParam("id").toLong()
val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("no vendor found with id $id")
ctx.status(HttpStatus.OK)
ctx.json(vendor)
}
data class VF(val common: CommonFilters, val vendorFilters: VendorFilters)
fun getAll(ctx: Context) {
val filters = ctx.bodyAsClass<VF>()
logger.info("filters = {}", filters)
val excel: String? = ctx.queryParam("excel")
val vendors = searchVendors(filters.common, filters.vendorFilters)
if (excel !== null) {
exportVendors(vendors)
val inputStream = FileInputStream("./excel/VendorList.xls")
ctx.result(inputStream).status(HttpStatus.OK)
} else {
ctx.json(vendors).status(HttpStatus.OK)
}
}
fun createBatch(ctx: Context) {
val vendors = ctx.bodyAsClass<List<Vendor>>()
database.saveAll(vendors)
}
fun create(ctx: Context) {
val vendor = ctx.bodyAsClass<Vendor>()
database.save(vendor)
ctx.result("vendor created")
ctx.status(HttpStatus.CREATED)
ctx.json(vendor)
}
fun update(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for $id")
val updatedVendor = ctx.bodyAsClass<Vendor>()
vendor.patchValues(updatedVendor)
vendor.update()
ctx.json(vendor).status(HttpStatus.OK)
}
fun delete(ctx: Context) {
}
fun getQuotes(ctx :Context){
val id = ctx.pathParam("id")
val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("no vendor found with id $id")
database.delete(vendor)
ctx.status(HttpStatus.OK)
}
fun getQuotes(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val quotes = database.find(Quotation::class.java)
.where()
.eq("vendor", id)
.eq("vendor", database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for $id"))
.findList()
ctx.json(quotes)
ctx.json(quotes).status(HttpStatus.OK)
}
fun getPos(ctx: Context) {
val id = ctx.pathParam("id")
val id = ctx.pathParam("id").toLong()
val pos = database.find(PurchaseOrder::class.java)
.where()
.eq("vendor", id)
.eq("vendor", database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for $id"))
.findList()
ctx.json(pos)
ctx.json(pos).status(HttpStatus.OK)
}
fun rate(ctx: Context) {
val id = ctx.pathParam("id")
val rating = ctx.pathParam("rating").toDouble()
val vendor = database.find(Vendor::class.java, id) ?: throw NotFoundResponse("vendor not found for id $id")
//could place some rating validation checks
vendor.rating = rating
vendor.save()
ctx.result("rating changed")
val rating1 = ctx.pathParam("rating").toDouble()
database.find(Vendor::class.java, id)?.let {
it.rating = rating1
it.save()
} ?: throw NotFoundResponse("vendor not found for id $id")
ctx.result("rating changed").status(HttpStatus.OK)
}
}
object RequestForQuote {
fun create(ctx: Context) {
val rfq = ctx.bodyAsClass<ReqForQuote>()
database.save(rfq)
//ctx.result("request for quote created")
//ctx.json(rfq)
//ctx.status(HttpStatus.CREATED)
//ctx.json("asss")
ctx.status(HttpStatus.CREATED)
ctx.json("asss")
}
fun get(ctx: Context) {
val id = ctx.pathParam("id")
val rfq = database.find(ReqForQuote::class.java, id) ?: throw NotFoundResponse("request for quote not found for id $id")
val rfq = database.find(ReqForQuote::class.java, id)
?: throw NotFoundResponse("request for quote not found for id $id")
ctx.status(HttpStatus.OK)
ctx.json(rfq)
}
fun update(ctx: Context) {
//shuld we compare the new body fields with preexisting ones and prepare a sql query to update those fields??
}
}
object IncomingInventoryCtrl {
fun create(ctx: Context) {
val ticket = ctx.bodyAsClass<IncomingInventory>()
database.save(ticket)
ctx.json(ticket).status(HttpStatus.CREATED)
}
fun update(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val ticket =
database.find(IncomingInventory::class.java, id) ?: throw NotFoundResponse("quote not found for $id")
val updatedTicket = ctx.bodyAsClass<IncomingInventory>()
ticket.patchValues(updatedTicket)
ticket.update()
ctx.json(ticket).status(HttpStatus.OK)
}
fun get(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val ticket = database.find(IncomingInventory::class.java, id)
?: throw NotFoundResponse("No incoming inventory ticket found with id $id")
ctx.json(ticket).status(HttpStatus.OK)
}
data class IIF(val common: CommonFilters, val incomingInventoryFilters: IncomingInventoryFilters)
fun getAll(ctx: Context) {
val filters = ctx.bodyAsClass<IIF>()
val tickets = searchIncomingInventory(filters.common, filters.incomingInventoryFilters)
val excel = ctx.queryParam("excel")
if (excel !== null) {
exportIncomingInventory(tickets)
val inputStream = FileInputStream("./excel/IncomingInventory.xls")
ctx.result(inputStream).status(HttpStatus.OK)
} else {
ctx.json(tickets).status(HttpStatus.OK)
}
}
fun getNextNum(ctx: Context) {
val prefix = "MRN/"
val cnt = database.find(IncomingInventory::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
}
object OutgoingInventoryCtrl {
fun create(ctx: Context) {
val ticket = ctx.bodyAsClass<OutgoingInventory>()
database.save(ticket)
ctx.json(ticket).status(HttpStatus.CREATED)
}
fun update(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val ticket =
database.find(OutgoingInventory::class.java, id) ?: throw NotFoundResponse("quote not found for $id")
val updatedTicket = ctx.bodyAsClass<OutgoingInventory>()
ticket.patchValues(updatedTicket)
ticket.update()
ctx.json(ticket).status(HttpStatus.OK)
}
fun get(ctx: Context) {
val id = ctx.pathParam("id").toLong()
val ticket = database.find(OutgoingInventory::class.java, id)
?: throw NotFoundResponse("No incoming inventory ticket found with id $id")
ctx.json(ticket).status(HttpStatus.OK)
}
data class OIF(val common: CommonFilters, val outgoingInventoryFilters: OutgoingInventoryFilters)
fun getAll(ctx: Context) {
val filters = ctx.bodyAsClass<OIF>()
val tickets = searchOutgoingInventory(filters.common, filters.outgoingInventoryFilters)
val excel = ctx.queryParam("excel")
if (excel !== null) {
exportOutgoingInventory(tickets)
val inputStream = FileInputStream("./excel/OutgoingInventory.xls")
ctx.result(inputStream).status(HttpStatus.OK)
} else {
ctx.json(tickets).status(HttpStatus.OK)
}
}
fun getNextNum(ctx: Context) {
println("inside next num")
val prefix = "MDN/"
val cnt = database.find(OutgoingInventory::class.java)
.findCount()
.toString()
.padStart(6, '0')
val seq = SequenceNumber(prefix + cnt)
ctx.json(seq).status(HttpStatus.OK)
}
}

View File

@@ -1,9 +1,587 @@
package com.restapi.controllers
import org.apache.poi
import com.google.gson.Gson
import com.restapi.domain.*
import com.restapi.domain.Document
import com.restapi.domain.PurchaseOrder
import com.restapi.domain.Quotation
import com.restapi.domain.Session.currentUser
import org.apache.poi.hssf.usermodel.HSSFSheet
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import com.restapi.domain.Session.database
import com.restapi.domain.Vendor
import org.apache.poi.hssf.usermodel.DVConstraint
import org.apache.poi.hssf.usermodel.HSSFDataValidation
import org.apache.poi.ss.usermodel.Cell
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.ss.usermodel.DateUtil
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.apache.poi.ss.util.CellRangeAddressList
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
enum class DataType {
QUOTE, PO, VENDOR
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.ZoneId
import java.util.*
fun createHeaderRow(cols: List<String>, sh: HSSFSheet, wb: Workbook) {
val boldFont = wb.createFont()
boldFont.bold = true
val style = wb.createCellStyle()
style.setFont(boldFont)
style.locked = true
sh.createRow(0).apply {
cols.forEachIndexed { index, value ->
val cell = createCell(index)
cell.setCellValue(value)
cell.setCellStyle(style)
}
fun CreateExcel(cols :List<String>, excelFor :DataType) {
}
}
fun String.parseDate(format: String): Date? {
val locale = Locale.getDefault()
return try {
SimpleDateFormat(format, locale).parse(this)
} catch (e: Exception) {
null
}
}
fun dateFromCellHelper(cell: Cell): LocalDate? {
val date = when (cell.cellType) {
CellType.STRING -> cell.stringCellValue.parseDate("yyyy-MM-dd")
CellType.NUMERIC -> {
if (DateUtil.isCellDateFormatted(cell)) {
cell.getDateCellValue()
} else {
null
}
}
else -> null
}
return date?.toInstant()?.atZone(ZoneId.systemDefault())?.toLocalDate()
}
fun stringFromCellHelper(cell: Cell): String {
val string = when (cell.cellType) {
CellType.NUMERIC -> cell.numericCellValue.toString()
CellType.STRING -> cell.stringCellValue
else -> ""
}
return string
}
fun doubleFromCellHelper(cell: Cell): Double {
val double = when (cell.cellType) {
CellType.NUMERIC -> cell.numericCellValue
CellType.STRING -> cell.stringCellValue.toDoubleOrNull()
else -> 0.0
}
return double ?: 0.0
}
fun longIntFromCellHelper(cell: Cell): Long {
val long = when (cell.cellType) {
CellType.NUMERIC -> cell.numericCellValue.toLong()
CellType.STRING -> cell.stringCellValue.toLong()
else -> 0
}
return long
}
enum class FileType {
QUOTES, POS, VENDORS, PRODS, DOCS
}
enum class EnumFor {
UOM, DocType
}
fun saveExcelFileLocally(fileName: String, wb: Workbook) {
val path = "./excel/"
val out = FileOutputStream(path + fileName)
wb.use {
it.write(out)
}
out.close()
}
fun TemplateExcelFile(fileType: FileType) {
when (fileType) {
FileType.QUOTES -> {
val headers: List<String> = listOf(
"Quotation Number",
"Date",
"Open Till",
"Product Id",
"Product Name",
"Product Unit Price",
"Quantity",
"Vendor Name",
"Vendor Address",
"RFQ Number",
"Total Amount",
"Terms and Conditions"
)
val wb = HSSFWorkbook()
val sh = wb.createSheet()
createHeaderRow(headers, sh, wb)
saveExcelFileLocally("Quotes_Template.xls", wb)
}
FileType.POS -> {
val headers: List<String> = listOf(
"Number",
"Date",
"Open Till",
"Reference Quotation Number",
"Vendor Name",
"Vendor Address",
"Product Id",
"Product Name",
"Unit Price",
"Quantity",
"Total Amount",
"Terms and Conditions"
)
val wb = HSSFWorkbook()
val sh = wb.createSheet()
createHeaderRow(headers, sh, wb)
saveExcelFileLocally("Purchase_Order_Template.xls", wb)
}
FileType.VENDORS -> {
val headers: List<String> = listOf(
"Name",
"MSME",
"GST Number",
"Address",
"Rating",
"Contact Name",
"Contact Email",
"Contact Mobile"
)
val wb = HSSFWorkbook()
val sh = wb.createSheet()
createHeaderRow(headers, sh, wb)
saveExcelFileLocally("Vendors_Template.xls", wb)
}
FileType.PRODS -> {
val headers: List<String> = listOf("Id", "Name", "Description", "HSN Code", "UOM")
val wb = HSSFWorkbook()
val sh = wb.createSheet()
createHeaderRow(headers, sh, wb)
val r0 = CellRangeAddressList(0, 1000, 4, 4)
val dv0 = HSSFDataValidation(
r0,
DVConstraint.createExplicitListConstraint(arrayOf("LTR", "MTR", "NOS", "ALL"))
).apply {
suppressDropDownArrow = true
}
sh.addValidationData(dv0)
saveExcelFileLocally("Products_Template.xls", wb)
}
FileType.DOCS -> {
}
}
}
fun exportQuotations(quotes: List<Quotation>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> = listOf(
"Quotation Number",
"Date",
"Open Till",
"Product Id",
"Product Name",
"Product Unit Price",
"Quantity",
"Vendor Name",
"Vendor Address",
"RFQ Number",
"Total AMount",
"Terms and Conditions"
)
createHeaderRow(headers, sh, wb)
var rowCnt = 1
for (quote in quotes) {
val prodCnt = quote.products.size
for (j in 0..<prodCnt) {
val row = sh.createRow(rowCnt++)
var i = 0;
row.createCell(i++).setCellValue(quote.quoteNum)
row.createCell(i++).setCellValue(quote.quoteDate)
row.createCell(i++).setCellValue(quote.validTill)
//6 would be repeated
row.createCell(i++).setCellValue(quote.products[j].productId)
row.createCell(i++).setCellValue(quote.products[j].productName)
row.createCell(i++).setCellValue(quote.products[j].unitPrice)
row.createCell(i++).setCellValue(quote.products[j].quantity)
row.createCell(i++).setCellValue(quote.vendor?.name)
row.createCell(i++).setCellValue(quote.vendor?.address)
row.createCell(i++).setCellValue(quote.reqForQuoteNum)
row.createCell(i++).setCellValue(quote.totalAmount)
row.createCell(i++).setCellValue(quote.tnc?.joinToString(";"))
}
}
saveExcelFileLocally("Quotes.xls", wb)
}
fun exportVendors(vendors: List<Vendor>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> =
listOf("No.", "Name", "MSME", "GST Number", "Address", "Rating", "Contact Name", "Contact Email", "Contact Mobile")
createHeaderRow(headers, sh, wb)
val totalCols = headers.size
var rowCnt = 1
for (vendor in vendors) {
val contactCnt = vendor.contacts.size
for (j in 0..<contactCnt) {
val row = sh.createRow(rowCnt++)
var i = 0
row.createCell(i++).setCellValue((rowCnt - 1).toString())
row.createCell(i++).setCellValue(vendor.name)
row.createCell(i++).setCellValue(vendor.msme)
row.createCell(i++).setCellValue(vendor.gstNumber)
row.createCell(i++).setCellValue(vendor.address)
row.createCell(i++).setCellValue(vendor.rating)
row.createCell(i++).setCellValue(vendor.contacts[j].name)
row.createCell(i++).setCellValue(vendor.contacts[j].email)
row.createCell(i++).setCellValue(vendor.contacts[j].mobile)
}
}
saveExcelFileLocally("VendorList.xls", wb)
}
fun exportProds(prods: List<Product>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> = listOf("Id", "Name", "Description", "HSN Code", "UOM")
createHeaderRow(headers, sh, wb)
var rowCnt = 1
for (prod in prods) {
val row = sh.createRow(rowCnt++)
var i = 0
row.createCell(i++).setCellValue(prod.id.toString())
row.createCell(i++).setCellValue(prod.name)
row.createCell(i++).setCellValue(prod.description)
row.createCell(i++).setCellValue(prod.hsnCode)
row.createCell(i++).setCellValue(prod.uom?.name)
}
saveExcelFileLocally("Products.xls", wb)
}
fun exportPos(pos: List<PurchaseOrder>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> = listOf(
"Number",
"Date",
"Open Till",
"Reference Quotation Number",
"Vendor Name",
"Vendor Address",
"Product Id",
"Product Name",
"Unit Price",
"Quantity",
"Total Amount",
"Terms and Conditions"
)
createHeaderRow(headers, sh, wb)
var rowCnt = 1
for (po in pos) {
val prodCnt = po.products.size
for (j in 0..<prodCnt) {
val row = sh.createRow(rowCnt++)
var i = 0
row.createCell(i++).setCellValue(po.poNum)
row.createCell(i++).setCellValue(po.poDate)
row.createCell(i++).setCellValue(po.validTill)
row.createCell(i++).setCellValue(po.referenceQuotation)
row.createCell(i++).setCellValue(po.vendor?.name)
row.createCell(i++).setCellValue(po.vendor?.address)
//6 would be repeated
row.createCell(i++).setCellValue(po.products[j].productId)
row.createCell(i++).setCellValue(po.products[j].productName)
row.createCell(i++).setCellValue(po.products[j].unitPrice)
row.createCell(i++).setCellValue(po.products[j].quantity)
row.createCell(i++).setCellValue(po.totalAmount)
row.createCell(i++).setCellValue(po.tnc?.joinToString(";"))
}
}
saveExcelFileLocally("Pos.xls", wb)
}
fun exportIncomingInventory(tickets : List<IncomingInventory>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> = listOf(
"MRN",
"Date",
"Vendor Name",
"Vendor Bill Number",
"Vendor Bill Amount",
"Product Id",
"Product Name",
"Unit Price",
"Quantity",
)
createHeaderRow(headers, sh, wb)
var rowCnt = 1
for (ticket in tickets) {
val prodCnt = ticket.products?.size
for (j in 0..<prodCnt!!) {
val row = sh.createRow(rowCnt++)
var i = 0
row.createCell(i++).setCellValue(ticket.mrn)
row.createCell(i++).setCellValue(ticket.date)
row.createCell(i++).setCellValue(ticket.vendor?.name)
row.createCell(i++).setCellValue(ticket.vendorBillNum)
row.createCell(i++).setCellValue(ticket.vendorBillAmount)
//6 would be repeated
row.createCell(i++).setCellValue(ticket.products!![j].productId)
row.createCell(i++).setCellValue(ticket.products!![j].productName)
row.createCell(i++).setCellValue(ticket.products!![j].unitPrice)
row.createCell(i++).setCellValue(ticket.products!![j].quantity)
}
}
saveExcelFileLocally("IncomingInventory.xls", wb)
}
fun exportOutgoingInventory(tickets : List<OutgoingInventory>) {
val wb = HSSFWorkbook()
val sh = wb.createSheet()
val headers: List<String> = listOf(
"MDN",
"Date",
"Out Mode",
"Purpose",
"Product Id",
"Product Name",
"Unit Price",
"Quantity",
)
createHeaderRow(headers, sh, wb)
var rowCnt = 1
for (ticket in tickets) {
val prodCnt = ticket.products?.size
for (j in 0..<prodCnt!!) {
val row = sh.createRow(rowCnt++)
var i = 0
row.createCell(i++).setCellValue(ticket.mdn)
row.createCell(i++).setCellValue(ticket.date)
row.createCell(i++).setCellValue(ticket.outMode.toString())
row.createCell(i++).setCellValue(ticket.purpose)
//6 would be repeated
row.createCell(i++).setCellValue(ticket.products!![j].productId)
row.createCell(i++).setCellValue(ticket.products!![j].productName)
row.createCell(i++).setCellValue(ticket.products!![j].unitPrice)
row.createCell(i++).setCellValue(ticket.products!![j].quantity)
}
}
saveExcelFileLocally("OutgoingInventory.xls", wb)
}
fun main() {
//ImportFromExcel(FileType.QUOTES, "C:\\Users\\arsalan\\Downloads\\Book.xlsx")
TemplateExcelFile(FileType.PRODS)
}
fun ImportFromExcel(fileType: FileType, filePath: String) {
val wb = WorkbookFactory.create(File(filePath))
val sh = wb.getSheetAt(0)
when (fileType) {
FileType.QUOTES -> {
//Quote Number, ProductName, Product Quantity, Total Amount, RFQ Number, Quote Date, Valid Till, TNC[], Documents[]
val quotesMap: MutableMap<String, Quotation> = mutableMapOf()
val quotesList: List<Quotation> = mutableListOf()
sh.rowIterator().forEach { row ->
if (row == null) {
//reached eof
return@forEach
}
val quoteNumber = stringFromCellHelper(row.getCell(0))
val quoteDt = dateFromCellHelper(row.getCell(1))
val rfqNum = stringFromCellHelper(row.getCell(2))
val quoteValidTill = dateFromCellHelper(row.getCell(3))
val vendorName = stringFromCellHelper(row.getCell(4))
val vendorGstNum = stringFromCellHelper(row.getCell(5))
val vendorAddress = stringFromCellHelper(row.getCell(6))
val prodName = stringFromCellHelper(row.getCell(7))
val prodQuantity = doubleFromCellHelper(row.getCell(8))
val prodUnitPrice = doubleFromCellHelper(row.getCell(9))
val totalQuoteAmount = doubleFromCellHelper(row.getCell(10))
val prod = POProducts("", prodName, prodUnitPrice, prodQuantity)
if (quotesMap.containsKey(quoteNumber)) {
//duplicated row
quotesMap.get(quoteNumber)?.products?.add(prod)
} else {
val v = Vendor()
v.apply {
name = vendorName
address = vendorAddress
gstNumber = vendorGstNum
}
val quote = Quotation()
quote.apply {
quoteNum = quoteNumber
quoteDate = quoteDt
reqForQuoteNum = rfqNum
validTill = quoteValidTill
products = mutableListOf(prod)
vendor = v
totalAmount = totalQuoteAmount
}
quotesMap.put(quoteNumber, quote)
}
}
//docs, tncs
// println("$quotesMap")
// quotesMap.forEach { (k, v) ->
// println("$v")
// }
}
FileType.POS -> {
//poNum, poDate, validTill, refQuoteNum, prodName, prodQuantity, totalAmount, products, vendorName, vendorGst, vendorAddress, tnc[]. docs[]
val PoMap: MutableMap<String, PurchaseOrder> = mutableMapOf()
sh.rowIterator().forEach { row ->
if (row == null) return@forEach
val poNum = stringFromCellHelper(row.getCell(0))
val poDate = dateFromCellHelper(row.getCell(1))
val refQuoteNum = stringFromCellHelper(row.getCell(2))
val poValidTill = dateFromCellHelper(row.getCell(3))
val prodName = stringFromCellHelper(row.getCell(4))
val prodQuantity = doubleFromCellHelper(row.getCell(5))
val vendorName = stringFromCellHelper(row.getCell(6))
val vendorGstNum = stringFromCellHelper(row.getCell(7))
val vendorAddress = stringFromCellHelper(row.getCell(8))
val totalPoAmount = doubleFromCellHelper(row.getCell(9))
//tncs, docs
val prod = POProducts("", prodName, 0.0, prodQuantity, "")
if (PoMap.containsKey(poNum)) {
//repeated row
PoMap.get(poNum)?.products?.add(prod)
} else {
val vendor = Vendor()
vendor.name = vendorName
vendor.address = vendorAddress
vendor.gstNumber = vendorGstNum
val po = PurchaseOrder()
po.poNum = poNum
po.poDate = poDate
po.referenceQuotation = refQuoteNum
po.validTill = poValidTill
PoMap.put(poNum, po)
}
}
}
FileType.VENDORS -> {
sh.rowIterator().forEach { row ->
//name, msme, gstNum, addresss, rating, contacts
if (row == null) return@forEach
val name = stringFromCellHelper(row.getCell(0))
val msme = stringFromCellHelper(row.getCell(1))
val gstNum = stringFromCellHelper(row.getCell(2))
val address = stringFromCellHelper(row.getCell(3))
val rating = doubleFromCellHelper(row.getCell(4))
//vendor object
val vendor = Vendor()
vendor.name = name
vendor.address = address
vendor.msme = msme
vendor.gstNumber = gstNum
vendor.rating = rating
}
}
FileType.PRODS -> {
sh.rowIterator().forEach { row ->
if (row == null) return@forEach
//id, name, description, hsnCode, uom
val prodId = longIntFromCellHelper(row.getCell(0))
val prodName = stringFromCellHelper(row.getCell(1))
val prodDesc = stringFromCellHelper(row.getCell(2))
val prodHsnCode = stringFromCellHelper(row.getCell(3))
val prodUom = stringFromCellHelper(row.getCell(4))
//new prod object
val prod = Product()
prod.id = prodId
prod.name = prodName
prod.description = prodDesc
prod.hsnCode = prodHsnCode
prod.uom = when (prodUom) {
"nos" -> UOM.NOS
"ltr" -> UOM.LTR
"mtr" -> UOM.MTR
else -> UOM.ALL
}
}
}
FileType.DOCS -> {
sh.rowIterator().forEach { row ->
//Document Name, Document Type, RefID, url
if (row == null) return@forEach
val docName = stringFromCellHelper(row.getCell(0))
val docType = stringFromCellHelper(row.getCell(1))
val refId = stringFromCellHelper(row.getCell(2))
val url = stringFromCellHelper(row.getCell(3))
//new doc object
val doc = Document()
doc.name = docName
doc.typeOfDoc = when (docType) {
"quote" -> DocType.QUOTE
"po" -> DocType.PO
"invoice" -> DocType.INVOICE
else -> DocType.ALL
}
doc.refIdOfDoc = refId.toLong()
doc.url = url
}
}
}
}

View File

@@ -1,28 +1,28 @@
package com.restapi.controllers
import com.restapi.domain.DocType
import com.restapi.domain.PurchaseOrder
import com.restapi.domain.Quotation
import com.restapi.domain.ReqForQuote
import com.restapi.domain.UOM
import java.time.LocalDate
import com.restapi.domain.*
import com.restapi.domain.Session.database
import java.time.LocalDate
//constants
const val IGNORE = "%"
val baseDate :LocalDate = LocalDate.MIN
val maxDate :LocalDate = LocalDate.MAX
val baseDate: LocalDate = LocalDate.of(1500, 1, 1)
val maxDate: LocalDate = LocalDate.of(3000, 1, 1)
const val RATING_MAX = 10.0
const val RATING_MIN = 0.0
//common filters would be used by most of the handlers
//require a list of vendor ids to be passed
data class CommonFilters(
val fromDate :LocalDate = baseDate,
val toDate :LocalDate = maxDate,
val from: LocalDate = baseDate,
val to: LocalDate = maxDate,
val vendor: List<Long>? = null,
val sortAsc: Boolean = true,
val sortBy: String = IGNORE
)
interface CustomFilters {}
data class POFilters(
val poNumLike: String = IGNORE,
val totalAmountExceeds: Long = Long.MIN_VALUE,
@@ -30,28 +30,35 @@ data class POFilters (
val validAfter: LocalDate = baseDate,
val validBefore: LocalDate = maxDate,
val refQuotation: String = IGNORE,
)
) : CustomFilters
data class ProductFilters(
val nameLike: String = IGNORE,
val hsnLike: String = IGNORE,
val uom: UOM = UOM.ALL,
)
) : CustomFilters
data class DocumentFilters(
val nameLike: String = IGNORE,
val typeOfDoc: DocType = DocType.ALL,
)
val docDateFrom: LocalDate = baseDate,
val docDataTo: LocalDate = maxDate,
) : CustomFilters
data class RFQFilters(
val validBefore: LocalDate = maxDate,
val validAfter: LocalDate = baseDate,
val reqForQuoteNumLike: String = IGNORE,
)
) : CustomFilters
data class QuoteFilters(
val quoteNumLike: String = IGNORE,
val validBefore :LocalDate = baseDate,
val validAfter :LocalDate = maxDate,
val validBefore: LocalDate = maxDate,
val validAfter: LocalDate = baseDate,
val totalAmountExceeds: Long = Long.MIN_VALUE,
val totalAmountLessThan: Long = Long.MAX_VALUE,
)
) : CustomFilters
data class VendorFilters(
val nameLike: String = IGNORE,
val msmeLike: String = IGNORE,
@@ -59,51 +66,91 @@ data class VendorFilters (
val addressLike: String = IGNORE,
val ratingExceeds: Double = RATING_MIN,
val ratingLessThan: Double = RATING_MAX,
)
) : CustomFilters
data class IncomingInventoryFilters(
val mrnLike: String = IGNORE,
val vehicleLike: String = IGNORE,
val vendorBillAmountExceeds: Double = Double.MIN_VALUE,
val vendorBillAmountLessThan: Double = Double.MAX_VALUE
) : CustomFilters
data class OutgoingInventoryFilters(
val mdnLike: String = IGNORE,
val purposeLike: String = IGNORE,
val personLike: String = IGNORE,
val vehicleLike: String = IGNORE,
val outMode: OutMode = OutMode.ALL
) : CustomFilters
fun <T> applyVendorHelper(q: io.ebean.ExpressionList<T>, vids: List<Long>?) {
if (vids.isNullOrEmpty()) return
q.apply {
q.`in`("vendor", vids)
}
// q.apply {
// q.`in`("vendor", vids)
// }
// println(vids)
// println(vids[0])
q.eq("vendor_sys_pk", vids[0])
}
fun <T> applySortHelper(q: io.ebean.ExpressionList<T>, sortBy: String, asc: Boolean) {
if (sortBy == IGNORE) return;
val order = if (asc) "ASC" else "DESC"
q.orderBy("$sortBy $order")
}
fun <T> applyFromToHelper(q: io.ebean.ExpressionList<T>, fromDate: LocalDate, toDate: LocalDate, colName: String) {
q.ge(colName, fromDate)
.le(colName, toDate)
}
fun <T> applyCommonFilters(q: io.ebean.ExpressionList<T>, commonFilters: CommonFilters) {
applyVendorHelper<T>(q, commonFilters.vendor)
applySortHelper<T>(q, commonFilters.sortBy, commonFilters.sortAsc)
}
fun searchQuotes(commonFilters: CommonFilters, quoteFilters: QuoteFilters): List<Quotation> {
val q = database.find(Quotation::class.java)
.where()
.between("quoteDate", commonFilters.fromDate, commonFilters.toDate)
.ilike("quoteNum", quoteFilters.quoteNumLike )
.ge("quoteDate", commonFilters.from)
.le("quoteDate", commonFilters.to)
.ge("validTill", quoteFilters.validAfter)
.le("validTill", quoteFilters.validBefore)
.le("totalAmount", quoteFilters.totalAmountLessThan)
.ge("totalAmount", quoteFilters.totalAmountExceeds)
.apply {
if(!commonFilters.vendor?.isEmpty()!!){
commonFilters.vendor.let { this.`in`("vendor", it) }
}
}
.le("totalAmount", quoteFilters.totalAmountLessThan)
.ilike("quoteNum", "%" + quoteFilters.quoteNumLike + "%")
applyFromToHelper(q, commonFilters.from, commonFilters.to, "quoteDate")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchVendors(commonFilters: CommonFilters, vendorFilters: VendorFilters): List<Vendor> {
val q = database.find(Vendor::class.java)
.where()
.ge("rating", vendorFilters.ratingExceeds)
.le("rating", vendorFilters.ratingLessThan)
.ilike("name", vendorFilters.nameLike)
.ilike("msme", vendorFilters.msmeLike)
.ilike("gstNum", vendorFilters.gstNumLike)
.ilike("address", vendorFilters.addressLike)
.ilike("name", "%" + vendorFilters.nameLike + "%")
.ilike("msme", "%" + vendorFilters.msmeLike + "%")
.ilike("gstNumber", "%" + vendorFilters.gstNumLike + "%")
.ilike("address", "%" + vendorFilters.addressLike + "%")
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchProducts(commonFilters: CommonFilters, productFilters: ProductFilters): List<Product> {
val q = database.find(Product::class.java)
.where()
.ilike("name", "%" + productFilters.nameLike + "%")
.ilike("hsnCode", "%" + productFilters.hsnLike + "%")
if (productFilters.uom != UOM.ALL) {
q.eq("uom", productFilters.uom)
}
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchDocs(commonFilters: CommonFilters, documentFilters: DocumentFilters): List<Document> {
val q = database.find(Document::class.java)
.where()
@@ -112,27 +159,70 @@ fun searchDocs(commonFilters: CommonFilters, documentFilters: DocumentFilters) :
this.eq("docType", documentFilters.typeOfDoc)
}
}
.ilike("name", documentFilters.nameLike )
.ilike("name", "%" + documentFilters.nameLike + "%")
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
applyVendorHelper(q, commonFilters.vendor)
return q.findList()
}
fun searchPos(commonFilters: CommonFilters, poFilters: POFilters) : List<PurchaseOrder> {
fun searchPos(commonFilters: CommonFilters, poFilters: POFilters?): List<PurchaseOrder> {
val poFilters = poFilters ?: POFilters()
val q = database.find(PurchaseOrder::class.java)
.where()
.between("totalAmount", poFilters.totalAmountExceeds, poFilters.totalAmountLessThan)
.between("validTill", poFilters.validAfter, poFilters.validBefore)
.ilike("poNum", poFilters.poNumLike )
.ilike("referenceQuotation", poFilters.refQuotation )
.ge("totalAmount", poFilters.totalAmountExceeds)
.le("totalAmount", poFilters.totalAmountLessThan)
.ge("validTill", poFilters.validAfter)
.le("validTill", poFilters.validBefore)
.ilike("poNum", "%" + poFilters.poNumLike + "%")
.ilike("referenceQuotation", "%" + poFilters.refQuotation + "%")
applyFromToHelper(q, commonFilters.from, commonFilters.to, "poDate")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchRFQ(commonFilters: CommonFilters, rfqFilters: RFQFilters): List<ReqForQuote> {
val q = database.find(ReqForQuote::class.java)
.where()
.between("validTill", rfqFilters.validAfter, rfqFilters.validBefore)
.ilike("reqForQuoteNum", rfqFilters.reqForQuoteNumLike)
.ge("validTill", rfqFilters.validAfter)
.le("validTill", rfqFilters.validBefore)
.ilike("reqForQuoteNum", "%" + rfqFilters.reqForQuoteNumLike + "%")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchIncomingInventory(
commonFilters: CommonFilters,
incomingInventoryFilters: IncomingInventoryFilters
): List<IncomingInventory> {
val q = database.find(IncomingInventory::class.java)
.where()
.ge("vendorBillAmount", incomingInventoryFilters.vendorBillAmountExceeds)
.le("vendorBillAmount", incomingInventoryFilters.vendorBillAmountLessThan)
.ilike("mrn", "%" + incomingInventoryFilters.mrnLike + "%")
.ilike("vehicle", "%" + incomingInventoryFilters.vehicleLike + "%")
applyFromToHelper(q, commonFilters.from, commonFilters.to, "date")
applyVendorHelper(q, commonFilters.vendor)
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}
fun searchOutgoingInventory(
commonFilters: CommonFilters,
outgoingInventoryFilters: OutgoingInventoryFilters
): List<OutgoingInventory> {
val q = database.find(OutgoingInventory::class.java)
.where()
.ilike("mdn", "%" + outgoingInventoryFilters.mdnLike + "%")
.ilike("purpose", "%" + outgoingInventoryFilters.purposeLike + "%")
// .ilike("person", "%" + outgoingInventoryFilters.personLike + "%")
//.ilike("vehicle", "%" + outgoingInventoryFilters.vehicleLike + "%")
if (outgoingInventoryFilters.outMode != OutMode.ALL) {
q.eq("outMode", outgoingInventoryFilters.outMode)
}
applyFromToHelper(q, commonFilters.from, commonFilters.to, "date")
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList()
}

View File

@@ -8,7 +8,7 @@ object DBMigration {
private fun create(){
val dbMigration: DbMigration = DbMigration.create()
dbMigration.setPlatform(Platform.POSTGRES)
//dbMigration.setGeneratePendingDrop("1.8")
dbMigration.generateMigration()
}

View File

@@ -12,7 +12,15 @@ import java.time.LocalDateTime
import javax.persistence.*
data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now())
data class POProducts(val productId: String = "", val unitPrice :Double = 0.0, val quantity: Double = 0.0, val description :String = "")
data class POProducts(
val productId: String = "",
val productName: String = "",
val unitPrice: Double = 0.0,
val quantity: Double = 0.0,
val description: String = ""
)
enum class ApprovalStatus {
PENDING, APPROVED, REJECTED
}
@@ -216,7 +224,6 @@ open class DataModel : BaseTenantModel() {
}
@Entity
@Index(unique = true, name = "unique_session_id", columnNames = ["session_id"])
open class AnonSession : BaseTenantModel() {
@@ -241,92 +248,213 @@ class SafeStringDeserializer : JsonDeserializer<String>() {
}
}
data class ContactPerson(val name: String, val email: String, val mobile: String)
data class ContactPerson(val name: String = "", val email: String = "", val mobile: String = "")
@Entity
open class Vendor : BaseTenantModel() {
fun patchValues(updatedVendor: Vendor) {
this.name = updatedVendor.name
this.msme = updatedVendor.msme
this.gstNumber = updatedVendor.gstNumber
this.address = updatedVendor.address
this.rating = updatedVendor.rating
this.contacts = updatedVendor.contacts
}
var name: String = ""
var msme: String = ""
var gstNumber: String = ""
var address: String = ""
var rating: Double = 0.0
@DbJsonB
var contacts: List<ContactPerson> = mutableListOf()
}
@Entity
open class PurchaseOrder : BaseTenantModel() {
fun patchValues(updatedPo: PurchaseOrder) {
this.poDate = updatedPo.poDate
this.validTill = updatedPo.validTill
this.tnc = updatedPo.tnc
this.products = updatedPo.products
this.vendor = updatedPo.vendor
this.documents = updatedPo.documents
this.totalAmount = updatedPo.totalAmount
}
@DbJsonB
var products: MutableList<POProducts> = mutableListOf()
@ManyToOne
var vendor: Vendor? = null
var referenceQuotation :String = ""
var totalAmount :Int = 0
var referenceQuotation: String? = ""
var totalAmount: Double = 0.0
var poNum: String = ""
var poDate: LocalDate? = null
var validTill: LocalDate? = null
@DbArray
var tnc: List<String> = arrayListOf()
var tnc: List<String>? = arrayListOf()
@DbArray
var documents: MutableList<Long> = arrayListOf()
var documents: List<String>? = arrayListOf()
}
enum class UOM {
NOS, LTR, MTR, ALL
}
enum class TypeOfProduct {
RAW_MATERIAL
}
@Entity
open class Product : BaseTenantModel() {
var id: Int? = null
fun patchValues(updatedProduct: Product) {
this.name = updatedProduct.name
this.description = updatedProduct.description
this.hsnCode = updatedProduct.hsnCode
this.uom = updatedProduct.uom
}
var id: Long? = null
var name: String = ""
var description: String = ""
var hsnCode: String = ""
@Enumerated(EnumType.STRING)
var uom: UOM? = null
@Enumerated(EnumType.STRING)
var type: TypeOfProduct? = null
}
@Entity
open class Quotation : BaseTenantModel() {
fun patchValues(updatedQuote: Quotation) {
this.quoteDate = updatedQuote.quoteDate
this.vendorQuoteNum = updatedQuote.vendorQuoteNum
this.validTill = updatedQuote.validTill
this.reqForQuoteNum = updatedQuote.reqForQuoteNum
this.tnc = updatedQuote.tnc
this.products = updatedQuote.products
this.vendor = updatedQuote.vendor
this.documents = updatedQuote.documents
this.totalAmount = updatedQuote.totalAmount
}
@DbJsonB
var products: MutableList<POProducts> = mutableListOf()
@ManyToOne
var vendor: Vendor? = null
var totalAmount :Long = 0
var totalAmount: Double = 0.0
var reqForQuoteNum: String = ""
var reqForQuoteNum: String? = ""
var quoteNum: String = ""
var vendorQuoteNum: String? = ""
var quoteDate: LocalDate? = null
var validTill: LocalDate? = null
@DbArray
var tnc: List<String> = arrayListOf()
@DbArray
var documents: MutableList<Long> = arrayListOf()
var tnc: List<String>? = arrayListOf()
@DbArray
var documents: List<String>? = arrayListOf()
var taxesIncluded: Boolean ?= null
}
enum class DocType {
PO, QUOTE, INVOICE, ALL
}
@Entity
open class Document : BaseTenantModel() {
var name: String = ""
@Enumerated(EnumType.STRING)
var typeOfDoc: DocType? = null
var refId: Long? = null
//could be quoteNum, PoNum, InvoiceNum
var refIdOfDoc: Long? = null
var description: String = ""
var url: String = ""
var docDate: LocalDate? = null
}
enum class RFQStatus {
DELIVERED, PO, QUOTE, CANCELLED
}
@Entity
open class ReqForQuote : BaseTenantModel() {
@DbArray
var potentialVendors: List<Long>? = null
@Enumerated(EnumType.STRING)
var status: RFQStatus? = null
// @DbArray
// var docs :List<Document>? = null
@DbJsonB
var products: List<POProducts>? = null
var reqForQuoteNum: String? = null
var openTill: LocalDate? = null
}
@Entity
open class IncomingInventory : BaseTenantModel() {
fun patchValues(updated: IncomingInventory) {
this.date = updated.date
this.vendorBillNum = updated.vendorBillNum
this.vendorBillAmount = updated.vendorBillAmount
this.vehicle = updated.vehicle
this.products = updated.products
this.vendor = updated.vendor
}
var mrn: String? = null
var date: LocalDate? = null
var vendorBillNum: String? = null
var vendorBillAmount: Double = 0.0
var vehicle: String = ""
@DbJsonB
var products: List<POProducts>? = null
@ManyToOne
var vendor: Vendor? = null
}
enum class OutMode {
PERSON, VEHICLE, ALL
}
@Entity
open class OutgoingInventory : BaseTenantModel() {
fun patchValues(updated: OutgoingInventory) {
this.date = updated.date
this.products = updated.products
this.purpose = updated.purpose
this.outMode = updated.outMode
this.person = updated.person
this.vehicle = updated.vehicle
}
var mdn: String? = null
var date: LocalDate? = null
@DbJsonB
var products: List<POProducts>? = null
var purpose: String? = null
@Enumerated(EnumType.STRING)
var outMode: OutMode? = null
var person: String? = null
var vehicle: String? = null
}

View File

@@ -0,0 +1,2 @@
-- apply alter tables
alter table incoming_inventory drop column vendor_bil_num;

View File

@@ -0,0 +1,3 @@
-- apply alter tables
alter table incoming_inventory drop column mdn;
alter table outgoing_inventory drop column mrn;

View File

@@ -0,0 +1,43 @@
-- drop dependencies
alter table document drop constraint if exists ck_document_type_of_doc;
alter table product drop constraint if exists ck_product_uom;
-- apply changes
create table req_for_quote (
sys_pk bigint generated by default as identity not null,
deleted_on timestamp,
current_approval_level integer default 0 not null,
required_approval_levels integer default 0 not null,
potential_vendors bigint[],
open_till date,
deleted boolean default false not null,
version integer default 1 not null,
created_at timestamp default 'now()' not null,
modified_at timestamp default 'now()' not null,
deleted_by varchar(255),
approval_status varchar(8) default 'APPROVED' not null,
tags varchar[] default '{}' not null,
comments jsonb default '[]' not null,
tenant_id varchar(255) not null,
status varchar(9),
products jsonb,
req_for_quote_num varchar(255),
created_by varchar(255) not null,
modified_by varchar(255) not null,
constraint ck_req_for_quote_approval_status check ( approval_status in ('PENDING','APPROVED','REJECTED')),
constraint ck_req_for_quote_status check ( status in ('DELIVERED','PO','QUOTE','CANCELLED')),
constraint pk_req_for_quote primary key (sys_pk)
);
-- apply alter tables
alter table document alter column type_of_doc type varchar(7) using type_of_doc::varchar(7);
alter table document alter column type_of_doc drop not null;
alter table document add column if not exists ref_id varchar(255);
alter table document add column if not exists doc_date date;
alter table product add column if not exists id bigint;
alter table purchase_order alter column reference_quotation drop not null;
alter table purchase_order alter column total_amount type float using total_amount::float;
alter table quotation alter column total_amount type float using total_amount::float;
alter table quotation add column if not exists req_for_quote_num varchar(255);
-- apply post alter
alter table document add constraint ck_document_type_of_doc check ( type_of_doc in ('PO','QUOTE','INVOICE','ALL'));
alter table product add constraint ck_product_uom check ( uom in ('NOS','LTR','MTR','ALL'));

View File

@@ -0,0 +1,8 @@
-- apply alter tables
alter table purchase_order alter column tnc drop not null;
alter table purchase_order alter column documents type varchar[] using documents::varchar[];
alter table purchase_order alter column documents drop not null;
alter table quotation alter column tnc drop not null;
alter table quotation alter column documents type varchar[] using documents::varchar[];
alter table quotation alter column documents drop not null;
alter table quotation add column if not exists vendor_quote_num varchar(255);

View File

@@ -0,0 +1,2 @@
-- apply alter tables
alter table document add column if not exists ref_id_of_doc bigint;

View File

@@ -0,0 +1,64 @@
-- apply changes
create table incoming_inventory (
sys_pk bigint generated by default as identity not null,
deleted_on timestamp,
current_approval_level integer default 0 not null,
required_approval_levels integer default 0 not null,
date date,
vendor_bill_amount float not null,
vendor_sys_pk bigint,
deleted boolean default false not null,
version integer default 1 not null,
created_at timestamp default 'now()' not null,
modified_at timestamp default 'now()' not null,
deleted_by varchar(255),
approval_status varchar(8) default 'APPROVED' not null,
tags varchar[] default '{}' not null,
comments jsonb default '[]' not null,
tenant_id varchar(255) not null,
mdn varchar(255) not null,
vendor_bil_num varchar(255) not null,
vehicle varchar(255) not null,
products jsonb,
created_by varchar(255) not null,
modified_by varchar(255) not null,
constraint ck_incoming_inventory_approval_status check ( approval_status in ('PENDING','APPROVED','REJECTED')),
constraint pk_incoming_inventory primary key (sys_pk)
);
create table outgoing_inventory (
sys_pk bigint generated by default as identity not null,
deleted_on timestamp,
current_approval_level integer default 0 not null,
required_approval_levels integer default 0 not null,
date date,
deleted boolean default false not null,
version integer default 1 not null,
created_at timestamp default 'now()' not null,
modified_at timestamp default 'now()' not null,
deleted_by varchar(255),
approval_status varchar(8) default 'APPROVED' not null,
tags varchar[] default '{}' not null,
comments jsonb default '[]' not null,
tenant_id varchar(255) not null,
mrn varchar(255) not null,
purpose varchar(255),
out_mode varchar(7),
person varchar(255),
vehicle varchar(255),
created_by varchar(255) not null,
modified_by varchar(255) not null,
constraint ck_outgoing_inventory_approval_status check ( approval_status in ('PENDING','APPROVED','REJECTED')),
constraint ck_outgoing_inventory_out_mode check ( out_mode in ('PERSON','VEHICLE','ALL')),
constraint pk_outgoing_inventory primary key (sys_pk)
);
-- apply alter tables
alter table product add column if not exists type varchar(12);
alter table quotation add column if not exists taxes_included boolean;
-- apply post alter
alter table product add constraint ck_product_type check ( type in ('RAW_MATERIAL'));
-- foreign keys and indices
create index ix_incoming_inventory_vendor_sys_pk on incoming_inventory (vendor_sys_pk);
alter table incoming_inventory add constraint fk_incoming_inventory_vendor_sys_pk foreign key (vendor_sys_pk) references vendor (sys_pk) on delete restrict on update restrict;

View File

@@ -0,0 +1,2 @@
-- apply alter tables
alter table incoming_inventory add column if not exists vendor_bill_num varchar(255);

View File

@@ -0,0 +1,4 @@
-- apply alter tables
alter table incoming_inventory add column if not exists mrn varchar(255);
alter table outgoing_inventory add column if not exists mdn varchar(255);
alter table outgoing_inventory add column if not exists products jsonb;

View File

@@ -0,0 +1,2 @@
-- apply alter tables
alter table document drop column ref_id;

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply" dropsFor="1.7">
<dropColumn columnName="vendor_bil_num" tableName="incoming_inventory"/>
</changeSet>
</migration>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply" dropsFor="1.8">
<dropColumn columnName="mdn" tableName="incoming_inventory"/>
<dropColumn columnName="mrn" tableName="outgoing_inventory"/>
</changeSet>
</migration>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<alterColumn columnName="type_of_doc" tableName="document" type="varchar(7)" currentType="varchar" notnull="false" currentNotnull="true" checkConstraint="check ( type_of_doc in ('PO','QUOTE','INVOICE','ALL'))" checkConstraintName="ck_document_type_of_doc"/>
<addColumn tableName="document">
<column name="ref_id" type="varchar"/>
<column name="doc_date" type="date"/>
</addColumn>
<alterColumn columnName="uom" tableName="product" checkConstraint="check ( uom in ('NOS','LTR','MTR','ALL'))" checkConstraintName="ck_product_uom"/>
<addColumn tableName="product">
<column name="id" type="bigint"/>
</addColumn>
<alterColumn columnName="reference_quotation" tableName="purchase_order" currentType="varchar" notnull="false" currentNotnull="true"/>
<alterColumn columnName="total_amount" tableName="purchase_order" type="double" currentType="integer" currentNotnull="true"/>
<alterColumn columnName="total_amount" tableName="quotation" type="double" currentType="integer" currentNotnull="true"/>
<addColumn tableName="quotation">
<column name="req_for_quote_num" type="varchar"/>
</addColumn>
<createTable name="req_for_quote" pkName="pk_req_for_quote">
<column name="sys_pk" type="bigint" primaryKey="true"/>
<column name="deleted_on" type="localdatetime"/>
<column name="deleted_by" type="varchar"/>
<column name="current_approval_level" type="integer" defaultValue="0" notnull="true"/>
<column name="required_approval_levels" type="integer" defaultValue="0" notnull="true"/>
<column name="approval_status" type="varchar(8)" defaultValue="'APPROVED'" notnull="true" checkConstraint="check ( approval_status in ('PENDING','APPROVED','REJECTED'))" checkConstraintName="ck_req_for_quote_approval_status"/>
<column name="tags" type="varchar[]" defaultValue="'{}'" notnull="true"/>
<column name="comments" type="jsonb" defaultValue="'[]'" notnull="true"/>
<column name="tenant_id" type="varchar" notnull="true"/>
<column name="potential_vendors" type="bigint[]"/>
<column name="status" type="varchar(9)" checkConstraint="check ( status in ('DELIVERED','PO','QUOTE','CANCELLED'))" checkConstraintName="ck_req_for_quote_status"/>
<column name="products" type="jsonb"/>
<column name="req_for_quote_num" type="varchar"/>
<column name="open_till" type="date"/>
<column name="deleted" type="boolean" defaultValue="false" notnull="true"/>
<column name="version" type="integer" defaultValue="1" notnull="true"/>
<column name="created_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="modified_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="created_by" type="varchar" notnull="true"/>
<column name="modified_by" type="varchar" notnull="true"/>
</createTable>
</changeSet>
</migration>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<alterColumn columnName="tnc" tableName="purchase_order" currentType="varchar[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="documents" tableName="purchase_order" type="varchar[]" currentType="bigint[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="tnc" tableName="quotation" currentType="varchar[]" notnull="false" currentNotnull="true"/>
<alterColumn columnName="documents" tableName="quotation" type="varchar[]" currentType="bigint[]" notnull="false" currentNotnull="true"/>
<addColumn tableName="quotation">
<column name="vendor_quote_num" type="varchar"/>
</addColumn>
</changeSet>
</migration>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<addColumn tableName="document">
<column name="ref_id_of_doc" type="bigint"/>
</addColumn>
</changeSet>
<changeSet type="pendingDrops">
<dropColumn columnName="ref_id" tableName="document"/>
</changeSet>
</migration>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<createTable name="incoming_inventory" pkName="pk_incoming_inventory">
<column name="sys_pk" type="bigint" primaryKey="true"/>
<column name="deleted_on" type="localdatetime"/>
<column name="deleted_by" type="varchar"/>
<column name="current_approval_level" type="integer" defaultValue="0" notnull="true"/>
<column name="required_approval_levels" type="integer" defaultValue="0" notnull="true"/>
<column name="approval_status" type="varchar(8)" defaultValue="'APPROVED'" notnull="true" checkConstraint="check ( approval_status in ('PENDING','APPROVED','REJECTED'))" checkConstraintName="ck_incoming_inventory_approval_status"/>
<column name="tags" type="varchar[]" defaultValue="'{}'" notnull="true"/>
<column name="comments" type="jsonb" defaultValue="'[]'" notnull="true"/>
<column name="tenant_id" type="varchar" notnull="true"/>
<column name="mdn" type="varchar" notnull="true"/>
<column name="date" type="date"/>
<column name="vendor_bil_num" type="varchar" notnull="true"/>
<column name="vendor_bill_amount" type="double" notnull="true"/>
<column name="vehicle" type="varchar" notnull="true"/>
<column name="products" type="jsonb"/>
<column name="vendor_sys_pk" type="bigint" references="vendor.sys_pk" foreignKeyName="fk_incoming_inventory_vendor_sys_pk" foreignKeyIndex="ix_incoming_inventory_vendor_sys_pk"/>
<column name="deleted" type="boolean" defaultValue="false" notnull="true"/>
<column name="version" type="integer" defaultValue="1" notnull="true"/>
<column name="created_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="modified_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="created_by" type="varchar" notnull="true"/>
<column name="modified_by" type="varchar" notnull="true"/>
</createTable>
<createTable name="outgoing_inventory" pkName="pk_outgoing_inventory">
<column name="sys_pk" type="bigint" primaryKey="true"/>
<column name="deleted_on" type="localdatetime"/>
<column name="deleted_by" type="varchar"/>
<column name="current_approval_level" type="integer" defaultValue="0" notnull="true"/>
<column name="required_approval_levels" type="integer" defaultValue="0" notnull="true"/>
<column name="approval_status" type="varchar(8)" defaultValue="'APPROVED'" notnull="true" checkConstraint="check ( approval_status in ('PENDING','APPROVED','REJECTED'))" checkConstraintName="ck_outgoing_inventory_approval_status"/>
<column name="tags" type="varchar[]" defaultValue="'{}'" notnull="true"/>
<column name="comments" type="jsonb" defaultValue="'[]'" notnull="true"/>
<column name="tenant_id" type="varchar" notnull="true"/>
<column name="mrn" type="varchar" notnull="true"/>
<column name="date" type="date"/>
<column name="purpose" type="varchar"/>
<column name="out_mode" type="varchar(7)" checkConstraint="check ( out_mode in ('PERSON','VEHICLE','ALL'))" checkConstraintName="ck_outgoing_inventory_out_mode"/>
<column name="person" type="varchar"/>
<column name="vehicle" type="varchar"/>
<column name="deleted" type="boolean" defaultValue="false" notnull="true"/>
<column name="version" type="integer" defaultValue="1" notnull="true"/>
<column name="created_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="modified_at" type="localdatetime" defaultValue="'now()'" notnull="true"/>
<column name="created_by" type="varchar" notnull="true"/>
<column name="modified_by" type="varchar" notnull="true"/>
</createTable>
<addColumn tableName="product">
<column name="type" type="varchar(12)" checkConstraint="check ( type in ('RAW_MATERIAL'))" checkConstraintName="ck_product_type"/>
</addColumn>
<addColumn tableName="quotation">
<column name="taxes_included" type="boolean"/>
</addColumn>
</changeSet>
</migration>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<addColumn tableName="incoming_inventory">
<column name="vendor_bill_num" type="varchar"/>
</addColumn>
</changeSet>
<changeSet type="pendingDrops">
<dropColumn columnName="vendor_bil_num" tableName="incoming_inventory"/>
</changeSet>
</migration>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<addColumn tableName="incoming_inventory">
<column name="mrn" type="varchar"/>
</addColumn>
<addColumn tableName="outgoing_inventory">
<column name="mdn" type="varchar"/>
<column name="products" type="jsonb"/>
</addColumn>
</changeSet>
<changeSet type="pendingDrops">
<dropColumn columnName="mdn" tableName="incoming_inventory"/>
<dropColumn columnName="mrn" tableName="outgoing_inventory"/>
</changeSet>
</migration>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply" dropsFor="1.5">
<dropColumn columnName="ref_id" tableName="document"/>
</changeSet>
</migration>

View File

@@ -1,4 +1,19 @@
<configuration>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>api.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>api.%d{yyyy-MM-dd}.%i.log.gz</FileNamePattern>
<MaxHistory>30</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
@@ -14,5 +29,6 @@
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="ROLLING" />
</root>
</configuration>