Browse Source

implemented seach in documents

module/search
Stephan Richter 2 months ago
parent
commit
379d156fd2
  1. 85
      documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java
  2. 12
      documents/src/main/java/de/srsoftware/umbrella/documents/DocumentDb.java
  3. 37
      documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java
  4. 33
      frontend/src/routes/search/Search.svelte

85
documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java

@ -22,9 +22,9 @@ import static de.srsoftware.umbrella.core.Constants.FIELD_PRICE_FORMAT; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);
}
}

12
documents/src/main/java/de/srsoftware/umbrella/documents/DocumentDb.java

@ -7,10 +7,8 @@ import de.srsoftware.umbrella.core.model.Document; @@ -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 { @@ -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 { @@ -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;

37
documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java

@ -2,8 +2,7 @@ @@ -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{ @@ -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) @@ -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 {

33
frontend/src/routes/search/Search.svelte

@ -10,6 +10,7 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -212,7 +223,7 @@
{#if times}
<fieldset>
<legend>
{t('timetracks')}
{t('timetracking')}
</legend>
<ul>
{#each Object.values(times) as time}
@ -227,3 +238,23 @@ @@ -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}

Loading…
Cancel
Save