Compare commits

...

9 Commits

Author SHA1 Message Date
7e8f70a7c2 UI 2024-02-05 09:42:06 +05:30
4688b92314 ExcelToDb complete 2024-01-24 18:33:01 +05:30
471c043218 merge complete 2024-01-24 17:49:30 +05:30
d8ab337fde Merge remote-tracking branch 'origin/master'
# Conflicts:
#	build.gradle.kts
#	src/main/kotlin/com/restapi/Main.kt
#	src/main/kotlin/com/restapi/controllers/Excel.kt
#	src/main/kotlin/com/restapi/controllers/Filters.kt
2024-01-24 17:46:49 +05:30
d23ac5261d Excel to Db 2024-01-24 11:25:18 +05:30
976aebec5b Product Excel Validation 2024-01-23 18:18:55 +05:30
a3f7614979 Product Excel Validation 2024-01-23 16:59:25 +05:30
8745db2127 Excel R/W 2024-01-22 15:12:58 +05:30
438daacdc6 ProductFilters 2024-01-19 17:47:18 +05:30
7 changed files with 282 additions and 68 deletions

View File

@@ -93,46 +93,6 @@ Authorization: {{auth-token}}
DELETE http://localhost:9001/api/vehicle/KA01HD6667 DELETE http://localhost:9001/api/vehicle/KA01HD6667
Authorization: {{auth-token}} Authorization: {{auth-token}}
### get po for id
GET http://localhost:9001/api/vendor/product
Authorization: {{auth-token}}
### get product for id
GET http://localhost:9001/api/vendor/product/7
Authorization: {{auth-token}}
### get row
GET http://localhost:9001/api/vendor/product/7
Authorization: Bearer {{auth-token}}
### create product
POST http://localhost:9001/api/vendor/product
Content-Type: application/json
Authorization: {{auth-token}}
{
"name": "Shirt",
"description": "Black Shirt",
"hsnCode": "BSM1XL"
}
### update field
PATCH http://localhost:9001/api/vendor/product/11
Content-Type: application/json
Authorization: {{auth-token}}
### upate a row
PUT http://localhost:9001/api/vendor/product/11
Content-Type: application/json
Authorization: {{auth-token}}
### delete a row
DELETE http://localhost:9001/api/vendor/product/2
Authorization: {{auth-token}}
### create vendor ### create vendor
POST http://localhost:9001/api/vendor/ POST http://localhost:9001/api/vendor/
Content-Type: application/json Content-Type: application/json
@@ -359,3 +319,38 @@ Authorization: {{auth-token}}
"quoteFilters": {} "quoteFilters": {}
} }
### CREATE PRODUCT
POST http://localhost:9001/api/vendor/product/create
Content-Type: application/json
Authorization: {{auth-token}}
{
"name" : "aa",
"description": "aa",
"hsnCode" : "aa",
"uom": "NOS"
}
### GET ALL PRODUCTS
GET http://localhost:9001/api/vendor/product/getAll
Authorization: {{auth-token}}
### GET PRODUCT BY KEY
GET http://localhost:9001/api/vendor/product/of/6
Authorization: {{auth-token}}
### GET PRODUCT BY HSNCODE
DELETE http://localhost:9001/api/vendor/product/3
Authorization: {{auth-token}}
### PRODUCT EXCEl
GET http://localhost:9001/api/vendor/product/to/excel
Authorization: {{auth-token}}
### EXCEL VALIDATE
GET http://localhost:9001/api/vendor/product/valid/excel
Authorization: {{auth-token}}
### EXCEL TO DB (IMPORT)
POST http://localhost:9001/api/vendor/product/excelToDb
Authorization: {{auth-token}}

View File

@@ -36,10 +36,9 @@ dependencies {
implementation("org.yaml:snakeyaml:2.2") implementation("org.yaml:snakeyaml:2.2")
implementation("io.minio:minio:8.5.7") implementation("io.minio:minio:8.5.7")
implementation("org.apache.httpcomponents:httpclient:4.5.14") implementation("org.apache.httpcomponents:httpclient:4.5.14")
implementation("org.apache.poi:poi:5.0.0") implementation("org.apache.poi:poi:5.2.3")
implementation("org.apache.poi:poi-ooxml:5.0.0") implementation("org.apache.poi:poi-ooxml:5.2.3")
implementation("com.google.code.gson:gson:2.8.8") implementation("com.google.code.gson:gson:2.8.8")
api ("net.cactusthorn.config:config-core:0.81") api ("net.cactusthorn.config:config-core:0.81")
api ("net.cactusthorn.config:config-yaml:0.81") api ("net.cactusthorn.config:config-yaml:0.81")
kapt("net.cactusthorn.config:config-compiler:0.81") kapt("net.cactusthorn.config:config-compiler:0.81")

View File

@@ -6,6 +6,8 @@ import com.restapi.config.AppConfig.Companion.appConfig
import com.restapi.config.Auth.validateAuthToken import com.restapi.config.Auth.validateAuthToken
import com.restapi.controllers.* import com.restapi.controllers.*
import com.restapi.domain.DataNotFoundException import com.restapi.domain.DataNotFoundException
import com.restapi.domain.Product
import com.restapi.domain.Session.a
import com.restapi.domain.Session.currentTenant import com.restapi.domain.Session.currentTenant
import com.restapi.domain.Session.currentUser import com.restapi.domain.Session.currentUser
import com.restapi.domain.Session.objectMapper import com.restapi.domain.Session.objectMapper
@@ -17,19 +19,20 @@ import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.* import io.javalin.apibuilder.ApiBuilder.*
import io.javalin.http.ContentType import io.javalin.http.ContentType
import io.javalin.http.Context import io.javalin.http.Context
import io.javalin.http.HandlerType
import io.javalin.http.UnauthorizedResponse import io.javalin.http.UnauthorizedResponse
import io.javalin.http.util.NaiveRateLimit import io.javalin.http.util.NaiveRateLimit
import io.javalin.http.util.RateLimitUtil import io.javalin.http.util.RateLimitUtil
import io.javalin.json.JavalinJackson import io.javalin.json.JavalinJackson
import org.jose4j.jwt.consumer.InvalidJwtException import org.jose4j.jwt.consumer.InvalidJwtException
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest
import java.time.LocalDateTime import java.time.LocalDateTime
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.jvm.optionals.getOrDefault import kotlin.jvm.optionals.getOrDefault
fun main(args: Array<String>) { fun main(args: Array<String>) {
val logger = LoggerFactory.getLogger("api") val logger = LoggerFactory.getLogger("api")
val adminRole = Role.Standard(Action.ADMIN) val adminRole = Role.Standard(Action.ADMIN)
@@ -77,6 +80,8 @@ fun main(args: Array<String>) {
TimeUnit.MINUTES TimeUnit.MINUTES
) )
if(ctx.method() == HandlerType.OPTIONS) return@before
val authToken = ctx.getAuthHeader() ?: throw UnauthorizedResponse() val authToken = ctx.getAuthHeader() ?: throw UnauthorizedResponse()
@@ -139,12 +144,15 @@ fun main(args: Array<String>) {
delete("/{id}", QuotationCtrl::delete, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN")))) delete("/{id}", QuotationCtrl::delete, Roles(Role.Explicit(listOf("ROLE_QUOTE_CREATE", "ROLE_ADMIN"))))
} }
path("/product") { path("/product") {
post("", ProductCtrl::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN", "ROLE_VENDOR_CREATE")))) post("/create", ProductCtrl::create, Roles(Role.Explicit(listOf("ROLE_PRODUCT_CREATE", "ROLE_ADMIN"))))
//get("/{hsnCode}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN")))) get("/getAll", ProductCtrl::getAll, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
get("/of/{key}", ProductCtrl::get, Roles(Role.Explicit(listOf("ROLE_PRODUCT_VIEW", "ROLE_ADMIN"))))
put("/{id}", ProductCtrl::update, Roles(Role.Explicit(listOf("ROLE_PRODUCT_UPDATE", "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")))) 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")))) 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")))) get("/to/excel", ProductCtrl::prodExcel)
get("/valid/excel") { ctx -> ctx.json(ExcelRead()) }
post("/excelToDb") {ctx -> ctx.json(excelToDb())}
} }
path("/doc"){ path("/doc"){
post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN")))) post("", Document::create, Roles(Role.Explicit(listOf("ROLE_DOC_CREATE", "ROLE_ADMIN"))))

View File

@@ -17,7 +17,11 @@ import com.restapi.integ.Scripting
import io.ebean.CallableSql import io.ebean.CallableSql
import io.ebean.RawSqlBuilder import io.ebean.RawSqlBuilder
import io.javalin.http.* import io.javalin.http.*
import org.apache.poi.ss.usermodel.WorkbookFactory
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.sql.Types import java.sql.Types
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -436,20 +440,19 @@ object PurchaseOrderCtrl {
data class ProductSearch( data class ProductSearch(
var isSort: String? = null var isSort: String? = null
) )
object ProductCtrl { object ProductCtrl {
fun get(ctx :Context){ fun get(ctx :Context){
val hsnCode = ctx.pathParam("hsnCode") val key = ctx.pathParam("key")
val product = database.find(Product::class.java, hsnCode) ?: throw NotFoundResponse("Product not found for $hsnCode") val product = database.find(Product::class.java, key) ?: throw NotFoundResponse("Product not found for $key")
ctx.json(product) ctx.json(product)
} }
fun getAll(ctx: Context){ fun getAll(ctx: Context){
val productList = Session.database.find(Product::class.java) val productList = database.find(Product::class.java)
.findList() .findList()
.sortedBy { it.hsnCode } //.removeAt(4)
ctx.json(productList) ctx.json(productList)
} }
@@ -461,7 +464,7 @@ object ProductCtrl {
fun delete(ctx: Context) { fun delete(ctx: Context) {
val id = ctx.pathParam("id") val id = ctx.pathParam("id")
val product = database.delete(Product::class.java, id) val product = database.deletePermanent(Product::class.java,id)
} }
fun patch(ctx: Context) { fun patch(ctx: Context) {
@@ -469,9 +472,41 @@ object ProductCtrl {
} }
fun update(ctx: Context) { fun update(ctx: Context) {
val id = ctx.pathParam("id") //have to implement
}
fun prodExcel(it: Context) {
val product = database.find(Product::class.java).findList()
it.result(CreateExcel(product)).contentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
.header("Content-Disposition", "attachment; filename=\"product.xlsx\"")
}
data class ProductList(
val name: String,
val description: String,
val hsnCode: String,
val uom: String?,
)
fun excelToDb(it: Context){
val inputStream = FileInputStream("C:\\Users\\vinay\\IdeaProjects\\readymixerp_modules_api_git\\Untitled 1.xlsx")
val workbook = WorkbookFactory.create(inputStream)
val workSheet = workbook.getSheetAt(0)
val dataList = mutableListOf<ProductList>()
for (row in workSheet) {
val cell1Value = row.getCell(0).stringCellValue
val cell2Value = row.getCell(1).stringCellValue
val cell3Value = row.getCell(2).stringCellValue
val cell4Value = row.getCell(3).stringCellValue
val data = ProductList(cell1Value, cell2Value, cell3Value, cell4Value)
dataList.add(data)
} }
database.saveAll(dataList)
}
} }
object QuotationCtrl { object QuotationCtrl {

View File

@@ -1,4 +1,7 @@
package com.restapi.controllers package com.restapi.controllers
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.gson.Gson import com.google.gson.Gson
import com.restapi.domain.* import com.restapi.domain.*
import com.restapi.domain.Document import com.restapi.domain.Document
@@ -11,15 +14,10 @@ import com.restapi.domain.Session.database
import com.restapi.domain.Vendor import com.restapi.domain.Vendor
import org.apache.poi.hssf.usermodel.DVConstraint import org.apache.poi.hssf.usermodel.DVConstraint
import org.apache.poi.hssf.usermodel.HSSFDataValidation import org.apache.poi.hssf.usermodel.HSSFDataValidation
import org.apache.poi.ss.usermodel.Cell import org.apache.poi.ss.usermodel.*
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 org.apache.poi.ss.util.CellRangeAddressList
import java.io.File import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.FileInputStream import java.io.*
import java.io.FileOutputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneId import java.time.ZoneId
@@ -389,7 +387,7 @@ fun ImportFromExcel(fileType: FileType, filePath : String) {
"nos" -> UOM.NOS "nos" -> UOM.NOS
"ltr" -> UOM.LTR "ltr" -> UOM.LTR
"mtr" -> UOM.MTR "mtr" -> UOM.MTR
else -> UOM.ALL else -> UOM.LTR
} }
} }
} }
@@ -417,3 +415,167 @@ fun ImportFromExcel(fileType: FileType, filePath : String) {
} }
} }
} }
data class validateExcel(
val name: String,
val description: String,
val hsnCode: String,
val ok: Boolean,
val err: String,
)
val app_common_om = jacksonObjectMapper().apply {
registerModule(JavaTimeModule())
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}
fun ExcelRead(): String{
val inputStream = FileInputStream("C:\\Users\\vinay\\IdeaProjects\\readymixerp_modules_api_git\\Untitled 1.xlsx")
val workbook = WorkbookFactory.create(inputStream)
val workSheet = workbook.getSheetAt(0)
var h = true
//Header check
if(workSheet.getRow(0).getCell(0).stringCellValue.equals("Name")) {
if (workSheet.getRow(0).getCell(1).stringCellValue.equals("Description")) {
if (workSheet.getRow(0).getCell(2).stringCellValue.equals("HSN")) {
if (workSheet.getRow(0).getCell(3).stringCellValue.equals("UOM")) {
h = false
}else return "Header UOM mismatch"
}else return "Header-HSN mismatch"
}else return "Header-Desc mismatch"
}else return "Header-Name mismatch"
val resp = arrayListOf<validateExcel>()
if(h==false) {
workSheet.rowIterator().forEach { row ->
if (row == null) return@forEach
if (h) {
val pName = row.getCell(0).run {
when {
this == null -> ""
this.cellType == CellType.STRING -> this.stringCellValue
else -> ""
}
}
val pDesc = row.getCell(1).run {
when {
this == null -> ""
this.cellType == CellType.STRING -> this.stringCellValue
else -> ""
}
}
val pHsn = row.getCell(2).run {
when {
this == null -> ""
this.cellType == CellType.STRING -> this.stringCellValue
else -> ""
}
}
if (pName.isEmpty() && pDesc.isEmpty() && pHsn.isEmpty()) {
return@forEach
}
if (pName.isEmpty()) {
resp.add(
validateExcel(
name = pName,
description = pDesc,
hsnCode = pHsn,
ok = false,
err = "Product name is required"
)
)
return@forEach
}
if (pDesc.isEmpty()) {
resp.add(
validateExcel(
name = pName,
description = pDesc,
hsnCode = pHsn,
ok = false,
err = "Product description is required"
)
)
return@forEach
}
if (pHsn.isEmpty()) {
resp.add(
validateExcel(
name = pName,
description = pDesc,
hsnCode = pHsn,
ok = false,
err = "Product HSN is required"
)
)
return@forEach
}
}
h = true
}
}
return app_common_om.writeValueAsString(resp)
}
fun CreateExcel(productList: List<Product>): InputStream {
val wb = XSSFWorkbook()
val sh = wb.createSheet()
val rows: Row = sh.createRow(0)
rows.createCell(0).setCellValue("Name")
rows.createCell(1).setCellValue("Description")
rows.createCell(2).setCellValue("HSN")
rows.createCell(3).setCellValue("UOM")
var rowNum = 1
for (product in productList) {
val row: Row = sh.createRow(rowNum++)
row.createCell(0).setCellValue(product.name)
row.createCell(1).setCellValue(product.description)
row.createCell(2).setCellValue(product.hsnCode)
val uomCell: Cell = row.createCell(3)
uomCell.setCellValue(product.uom?.name ?: "")
}
val baos = ByteArrayOutputStream()
wb.write(baos)
wb.close()
return ByteArrayInputStream(baos.toByteArray())
}
fun excelToDb(): List<Product> {
val inputStream = FileInputStream("C:\\Users\\vinay\\IdeaProjects\\readymixerp_modules_api_git\\Untitled 1.xlsx")
val workbook = WorkbookFactory.create(inputStream)
val workSheet = workbook.getSheetAt(0)
for (row in workSheet) {
val cell1Value = row.getCell(0).stringCellValue
val cell2Value = row.getCell(1).stringCellValue
val cell3Value = row.getCell(2).stringCellValue
val cell4Value = row?.getCell(3)?.stringCellValue
val prod = Product()
prod.name = cell1Value
prod.description = cell2Value
prod.hsnCode = cell3Value
prod.uom = when(cell4Value) {
"nos" -> UOM.NOS
"ltr" -> UOM.LTR
"mtr" -> UOM.MTR
else -> UOM.ALL
}
database.saveAll(prod)
}
val productList = Session.database.find(Product::class.java).findList()
return productList
}

View File

@@ -29,10 +29,14 @@ data class POFilters (
val validBefore: LocalDate = maxDate, val validBefore: LocalDate = maxDate,
val refQuotation :String = IGNORE, val refQuotation :String = IGNORE,
) : CustomFilters ) : CustomFilters
enum class UOMFilter {
ALL //fixme: later
}
data class ProductFilters ( data class ProductFilters (
val nameLike :String = IGNORE, val nameLike :String = IGNORE,
val hsnLike :String = IGNORE, val hsnLike :String = IGNORE,
val uom :UOM = UOM.ALL, val uom :UOMFilter = UOMFilter.ALL,
) : CustomFilters ) : CustomFilters
data class DocumentFilters ( data class DocumentFilters (
val nameLike :String = IGNORE, val nameLike :String = IGNORE,
@@ -142,3 +146,12 @@ fun searchRFQ(commonFilters: CommonFilters, rfqFilters: RFQFilters) : List<ReqFo
applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc) applySortHelper(q, commonFilters.sortBy, commonFilters.sortAsc)
return q.findList() return q.findList()
} }
fun searchProduct(commonFilters: CommonFilters, productFilters: ProductFilters): List<Product> {
val p = database.find(Product::class.java)
.where()
.ilike("hsnCode", productFilters.hsnLike)
.ilike("Pname", productFilters.nameLike)
applySortHelper(p, commonFilters.sortBy, commonFilters.sortAsc)
return p.findList()
}

View File

@@ -9,6 +9,7 @@ import io.ebean.annotation.*
import io.ebean.annotation.Index import io.ebean.annotation.Index
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.util.*
import javax.persistence.* import javax.persistence.*
data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now()) data class Comments(val text: String = "", val by: String = "", val at: LocalDateTime = LocalDateTime.now())
@@ -274,6 +275,7 @@ open class PurchaseOrder :BaseTenantModel() {
enum class UOM { enum class UOM {
NOS, LTR, MTR, ALL NOS, LTR, MTR, ALL
} }
@Entity @Entity
open class Product :BaseTenantModel() { open class Product :BaseTenantModel() {
var id: Long? = null var id: Long? = null