implemented seach in documents
This commit is contained in:
@@ -22,9 +22,9 @@ import static de.srsoftware.umbrella.core.Constants.FIELD_PRICE_FORMAT;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_TIME_ID;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_TYPE;
|
||||
import static de.srsoftware.umbrella.core.Constants.FIELD_UNIT;
|
||||
import static de.srsoftware.umbrella.core.Paths.LIST;
|
||||
import static de.srsoftware.umbrella.core.Paths.STATES;
|
||||
import static de.srsoftware.umbrella.core.Paths.*;
|
||||
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE;
|
||||
import static de.srsoftware.umbrella.core.Util.mapValues;
|
||||
import static de.srsoftware.umbrella.core.Util.request;
|
||||
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
|
||||
import static de.srsoftware.umbrella.core.model.Document.State.NEW;
|
||||
@@ -52,6 +52,7 @@ import de.srsoftware.tools.SessionToken;
|
||||
import de.srsoftware.tools.Tuple;
|
||||
import de.srsoftware.umbrella.core.BaseHandler;
|
||||
import de.srsoftware.umbrella.core.ModuleRegistry;
|
||||
import de.srsoftware.umbrella.core.Paths;
|
||||
import de.srsoftware.umbrella.core.api.*;
|
||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||
import de.srsoftware.umbrella.core.model.*;
|
||||
@@ -148,7 +149,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
yield switch (head){
|
||||
case null -> getDocument(ex,docId,user.get());
|
||||
case PATH_PDF -> getRenderedDocument(ex,docId,user.get());
|
||||
case SETTINGS -> getDocumentSettings(ex,docId,user.get());
|
||||
case Paths.SETTINGS -> getDocumentSettings(ex,docId,user.get());
|
||||
default -> super.doGet(path,ex);
|
||||
};
|
||||
}
|
||||
@@ -191,7 +192,8 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
if (user.isEmpty()) return unauthorized(ex);
|
||||
var head = path.pop();
|
||||
return switch (head){
|
||||
case LIST -> listCompaniesDocuments(ex,user.get(),token.orElse(null));
|
||||
case LIST -> listCompaniesDocuments(ex,user.get());
|
||||
case SEARCH -> postSearch(ex,user.get());
|
||||
case TEMPLATES -> postTemplateList(ex,user.get());
|
||||
case null -> postDocument(ex,user.get());
|
||||
default -> postToDocument(ex,path,user.get(),Long.parseLong(head));
|
||||
@@ -203,27 +205,6 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
|
||||
var doc = getDocumentWithCompanyData(docId,user);
|
||||
var rendered = renderDocument(doc,user);
|
||||
var json = json(ex);
|
||||
if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL);
|
||||
if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingFieldException(SUBJECT);
|
||||
if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingFieldException(CONTENT);
|
||||
var settings = new CustomerSettings(doc.head(),doc.footer(),content);
|
||||
try {
|
||||
db.save(settings,doc);
|
||||
} catch (UmbrellaException e) {
|
||||
LOG.log(WARNING,e);
|
||||
}
|
||||
var attachment = new Attachment(doc.number()+".pdf",rendered.mimeType(),rendered.bytes());
|
||||
var message = new Message(user,subject,content,null,List.of(attachment));
|
||||
var envelope = new Envelope(message,new User(doc.customer().shortName(),new EmailAddress(email),doc.customer().language()));
|
||||
postBox().send(envelope);
|
||||
db.save(doc.set(SENT));
|
||||
return ok(ex);
|
||||
}
|
||||
|
||||
private boolean getContacts(HttpExchange ex, UmbrellaUser user, Token token) throws IOException, UmbrellaException {
|
||||
return sendContent(ex,getLegacyContacts(ex,user,token));
|
||||
}
|
||||
@@ -274,15 +255,6 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
return sendContent(ex,settings);
|
||||
}
|
||||
|
||||
private PriceFormat priceFormat(String currency, String language) {
|
||||
var pattern = switch (currency){
|
||||
case "$" -> "$ {0,number,#,###.00}";
|
||||
default -> "{0,number,#,###.00} "+currency;
|
||||
};
|
||||
var message = new MessageFormat(pattern, "de".equals(language)? Locale.GERMAN:Locale.US);
|
||||
return val -> message.format(new Object[]{val/100d});
|
||||
}
|
||||
|
||||
private DocumentData convert(Document document) throws UmbrellaException {
|
||||
var currency = switch (document.currency()){
|
||||
case "€" -> Currency.EUR;
|
||||
@@ -392,6 +364,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
return content;
|
||||
|
||||
}
|
||||
|
||||
private boolean getRenderedDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException {
|
||||
var document = getDocumentWithCompanyData(docId,user);
|
||||
var content = renderDocument(document,user);
|
||||
@@ -412,8 +385,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
return db.listDocs(companyId);
|
||||
}
|
||||
|
||||
|
||||
private boolean listCompaniesDocuments(HttpExchange ex, UmbrellaUser user, Token token) throws UmbrellaException {
|
||||
private boolean listCompaniesDocuments(HttpExchange ex, UmbrellaUser user) throws UmbrellaException {
|
||||
try {
|
||||
var json = json(ex);
|
||||
if (!json.has(COMPANY)) throw missingFieldException(COMPANY);
|
||||
@@ -556,6 +528,17 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
return sendContent(ex,templates.stream().map(Template::toMap));
|
||||
}
|
||||
|
||||
private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException {
|
||||
var json = json(ex);
|
||||
if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY);
|
||||
var keys = Arrays.asList(key.split(" "));
|
||||
var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val;
|
||||
|
||||
var userCompanyIds = companyService().listCompaniesOf(user).keySet();
|
||||
|
||||
var documents = db.find(userCompanyIds,keys,fulltext);
|
||||
return sendContent(ex,mapValues(documents));
|
||||
}
|
||||
|
||||
private boolean postToDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
|
||||
var head = path.pop();
|
||||
@@ -566,4 +549,34 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
||||
case null, default -> super.doPost(path,ex);
|
||||
};
|
||||
}
|
||||
|
||||
private PriceFormat priceFormat(String currency, String language) {
|
||||
var pattern = switch (currency){
|
||||
case "$" -> "$ {0,number,#,###.00}";
|
||||
default -> "{0,number,#,###.00} "+currency;
|
||||
};
|
||||
var message = new MessageFormat(pattern, "de".equals(language)? Locale.GERMAN:Locale.US);
|
||||
return val -> message.format(new Object[]{val/100d});
|
||||
}
|
||||
|
||||
private boolean sendDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException {
|
||||
var doc = getDocumentWithCompanyData(docId,user);
|
||||
var rendered = renderDocument(doc,user);
|
||||
var json = json(ex);
|
||||
if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL);
|
||||
if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingFieldException(SUBJECT);
|
||||
if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingFieldException(CONTENT);
|
||||
var settings = new CustomerSettings(doc.head(),doc.footer(),content);
|
||||
try {
|
||||
db.save(settings,doc);
|
||||
} catch (UmbrellaException e) {
|
||||
LOG.log(WARNING,e);
|
||||
}
|
||||
var attachment = new Attachment(doc.number()+".pdf",rendered.mimeType(),rendered.bytes());
|
||||
var message = new Message(user,subject,content,null,List.of(attachment));
|
||||
var envelope = new Envelope(message,new User(doc.customer().shortName(),new EmailAddress(email),doc.customer().language()));
|
||||
postBox().send(envelope);
|
||||
db.save(doc.set(SENT));
|
||||
return ok(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,8 @@ import de.srsoftware.umbrella.core.model.Document;
|
||||
import de.srsoftware.umbrella.core.model.Template;
|
||||
import de.srsoftware.umbrella.core.model.Type;
|
||||
import de.srsoftware.umbrella.documents.model.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public interface DocumentDb {
|
||||
Long dropPosition(long documentId, long pos) throws UmbrellaException;
|
||||
@@ -22,6 +20,10 @@ public interface DocumentDb {
|
||||
*/
|
||||
String deleteDoc(Long docId) throws UmbrellaException;
|
||||
|
||||
public Map<Long, Map<Long, String>> docReferencedByTimes(Set<Long> timeIds) throws UmbrellaException;
|
||||
|
||||
Map<Long, Document> find(Collection<Long> companyIds, List<String> keys, boolean fulltext);
|
||||
|
||||
Long getCustomerPrice(long company, String id, String itemCode) throws UmbrellaException;
|
||||
|
||||
CustomerSettings getCustomerSettings(long companyId, Type docType, String customerId) throws UmbrellaException;
|
||||
@@ -32,8 +34,6 @@ public interface DocumentDb {
|
||||
|
||||
Type getType(int typeId) throws UmbrellaException;
|
||||
|
||||
public Map<Long, Map<Long, String>> docReferencedByTimes(Set<Long> timeIds) throws UmbrellaException;
|
||||
|
||||
Map<Long, Document> listDocs(long companyId) throws UmbrellaException;
|
||||
|
||||
HashMap<Integer, Type> listTypes() throws UmbrellaException;
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
package de.srsoftware.umbrella.documents;
|
||||
|
||||
|
||||
import static de.srsoftware.tools.jdbc.Condition.equal;
|
||||
import static de.srsoftware.tools.jdbc.Condition.in;
|
||||
import static de.srsoftware.tools.jdbc.Condition.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.*;
|
||||
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
|
||||
import static de.srsoftware.umbrella.core.Constants.*;
|
||||
@@ -31,12 +30,8 @@ public class SqliteDb implements DocumentDb{
|
||||
private static final System.Logger LOG = System.getLogger(SqliteDb.class.getSimpleName());
|
||||
private final Connection db;
|
||||
private static final String DB_VERSION = "message_db_version";
|
||||
|
||||
|
||||
private static final int INITIAL_DB_VERSION = 1;
|
||||
|
||||
|
||||
|
||||
public SqliteDb(Connection conn){
|
||||
db = conn;
|
||||
init();
|
||||
@@ -334,6 +329,36 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Document> find(Collection<Long> companyIds, List<String> keys, boolean fulltext) {
|
||||
try {
|
||||
var rs = Query.select(ALL).from(TABLE_DOCUMENT_TYPES).exec(db);
|
||||
var types = new HashMap<Integer,Type>();
|
||||
while (rs.next()) types.put(rs.getInt(ID),toType(rs));
|
||||
rs.close();
|
||||
|
||||
var query = Query.select(ALL).from(TABLE_DOCUMENTS).where(COMPANY_ID,in(companyIds.toArray()));
|
||||
for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4},\" \",{5},\" \",{6},\" \",{7},\" \",{8},\" \",{9})",NUMBER,FIELD_HEAD,FIELD_FOOTER,SENDER,FIELD_TAX_NUMBER,FIELD_BANK_ACCOUNT,FIELD_CUSTOMER,FIELD_CUSTOMER_NUMBER,FIELD_CUSTOMER_TAX_NUMBER,FIELD_CUSTOMER_EMAIL),like("%"+key+"%"));
|
||||
rs = query.exec(db);
|
||||
var map = new HashMap<Long,Document>();
|
||||
while (rs.next()) map.put(rs.getLong(ID),toDoc(rs,types));
|
||||
rs.close();
|
||||
|
||||
rs = Query.select(ALL).from(TABLE_POSITIONS).where(FIELD_DOCUMENT_ID,in(map.keySet().toArray())).exec(db);
|
||||
while (rs.next()){
|
||||
var docId = rs.getLong(FIELD_DOCUMENT_ID);
|
||||
var position = toPosition(rs);
|
||||
map.get(docId).positions().add(position);
|
||||
position.clean();
|
||||
}
|
||||
rs.close();
|
||||
return map;
|
||||
} catch (SQLException e) {
|
||||
LOG.log(WARNING,"Failed to search list of documents.");
|
||||
throw new UmbrellaException(500,"Failed to search list of documents.").causedBy(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Document> listDocs(long companyId) throws UmbrellaException {
|
||||
try {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
const router = useTinyRouter();
|
||||
let bookmarks = $state(null);
|
||||
let companies = $state(null);
|
||||
let documents = $state(null);
|
||||
let error = $state(null);
|
||||
let fulltext = false;
|
||||
let key = $state(router.getQueryParam('key'));
|
||||
@@ -43,6 +44,7 @@
|
||||
};
|
||||
fetch(api('bookmark/search'),options).then(handleBookmarks);
|
||||
fetch(api('company/search'),options).then(handleCompanies);
|
||||
fetch(api('document/search'),options).then(handleDocuments);
|
||||
fetch(api('notes/search'),options).then(handleNotes);
|
||||
fetch(api('project/search'),options).then(handleProjects);
|
||||
fetch(api('task/search'),options).then(handleTasks);
|
||||
@@ -76,6 +78,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDocuments(resp){
|
||||
if (resp.ok){
|
||||
const json = await resp.json();
|
||||
documents = Object.keys(json).length ? json : null;
|
||||
} else {
|
||||
error = await resp.text();
|
||||
}
|
||||
}
|
||||
|
||||
async function handleNotes(resp){
|
||||
if (resp.ok){
|
||||
const json = await resp.json();
|
||||
@@ -212,7 +223,7 @@
|
||||
{#if times}
|
||||
<fieldset>
|
||||
<legend>
|
||||
{t('timetracks')}
|
||||
{t('timetracking')}
|
||||
</legend>
|
||||
<ul>
|
||||
{#each Object.values(times) as time}
|
||||
@@ -227,3 +238,23 @@
|
||||
</ul>
|
||||
</fieldset>
|
||||
{/if}
|
||||
{#if documents}
|
||||
<fieldset>
|
||||
<legend>
|
||||
{t('documents')}
|
||||
</legend>
|
||||
<ul>
|
||||
{#each Object.values(documents) as document}
|
||||
<li>
|
||||
<a href="/document/{document.id}/view" {onclick} >
|
||||
{document.number}
|
||||
({document.date})
|
||||
{document.sender.name.split('\n')[0]}
|
||||
→
|
||||
{document.customer.name.split('\n')[0]}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user