Compare commits
4 Commits
module/doc
...
module/pro
| Author | SHA1 | Date | |
|---|---|---|---|
| 11c0983dac | |||
| c37df2ddec | |||
| 93907a839d | |||
| ccb84995cb |
@@ -1,6 +1,7 @@
|
|||||||
/* © SRSoftware 2025 */
|
/* © SRSoftware 2025 */
|
||||||
package de.srsoftware.umbrella.core.model;
|
package de.srsoftware.umbrella.core.model;
|
||||||
|
|
||||||
|
import static de.srsoftware.tools.Optionals.emptyIfNull;
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
import static de.srsoftware.umbrella.core.Constants.*;
|
||||||
import static de.srsoftware.umbrella.core.Field.*;
|
import static de.srsoftware.umbrella.core.Field.*;
|
||||||
import static de.srsoftware.umbrella.core.Field.COMPANY;
|
import static de.srsoftware.umbrella.core.Field.COMPANY;
|
||||||
@@ -57,14 +58,14 @@ public final class Document implements Mappable {
|
|||||||
private final Type type;
|
private final Type type;
|
||||||
private LocalDate date;
|
private LocalDate date;
|
||||||
private State state;
|
private State state;
|
||||||
private Template template;
|
private String template;
|
||||||
private final Sender sender;
|
private final Sender sender;
|
||||||
private final Customer customer;
|
private final Customer customer;
|
||||||
private final PositionList positions;
|
private final PositionList positions;
|
||||||
private final Set<String> dirtyFields = new HashSet<>();
|
private final Set<String> dirtyFields = new HashSet<>();
|
||||||
|
|
||||||
|
|
||||||
public Document(long id, long companyId, String number, Type type, LocalDate date, State state, Template template, String delivery, String head, String footer, String currency, String decimalSeparator, Sender sender, Customer customer, PositionList positions) {
|
public Document(long id, long companyId, String number, Type type, LocalDate date, State state, String template, String delivery, String head, String footer, String currency, String decimalSeparator, Sender sender, Customer customer, PositionList positions) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.companyId = companyId;
|
this.companyId = companyId;
|
||||||
this.number = number;
|
this.number = number;
|
||||||
@@ -206,7 +207,7 @@ public final class Document implements Mappable {
|
|||||||
case SENDER: if (json.get(key) instanceof JSONObject nested) sender.patch(nested); break;
|
case SENDER: if (json.get(key) instanceof JSONObject nested) sender.patch(nested); break;
|
||||||
case STATE: state = State.of(json.getInt(key)).orElseThrow(() -> new UmbrellaException(HTTP_UNPROCESSABLE,"Invalid state")); break;
|
case STATE: state = State.of(json.getInt(key)).orElseThrow(() -> new UmbrellaException(HTTP_UNPROCESSABLE,"Invalid state")); break;
|
||||||
case POS: if (json.get(key) instanceof JSONObject nested) positions.patch(nested); break;
|
case POS: if (json.get(key) instanceof JSONObject nested) positions.patch(nested); break;
|
||||||
case TEMPLATE_ID: if (json.get(key) instanceof Number num) template = new Template(num.longValue(),companyId,null,null); break;
|
case TEMPLATE_ID: if (json.get(key) instanceof String templateId) template = templateId; break;
|
||||||
default: key = null;
|
default: key = null;
|
||||||
}
|
}
|
||||||
if (key != null) dirtyFields.add(key);
|
if (key != null) dirtyFields.add(key);
|
||||||
@@ -225,7 +226,7 @@ public final class Document implements Mappable {
|
|||||||
map.put(TYPE, type.name());
|
map.put(TYPE, type.name());
|
||||||
map.put(DATE, date);
|
map.put(DATE, date);
|
||||||
map.put(STATE, state.code);
|
map.put(STATE, state.code);
|
||||||
map.put(DELIVERY, delivery == null ? "" : delivery);
|
map.put(DELIVERY, emptyIfNull(delivery));
|
||||||
map.put(HEAD, mapMarkdown(head));
|
map.put(HEAD, mapMarkdown(head));
|
||||||
map.put(FOOTER, mapMarkdown(footer));
|
map.put(FOOTER, mapMarkdown(footer));
|
||||||
map.put(CURRENCY, currency);
|
map.put(CURRENCY, currency);
|
||||||
@@ -235,7 +236,7 @@ public final class Document implements Mappable {
|
|||||||
map.put("taxes",positions.taxNetSums(true));
|
map.put("taxes",positions.taxNetSums(true));
|
||||||
map.put(NET_SUM, netSum());
|
map.put(NET_SUM, netSum());
|
||||||
map.put(GROSS_SUM, grossSum());
|
map.put(GROSS_SUM, grossSum());
|
||||||
if (template != null) map.put("template", template.toMap());
|
map.put("template", emptyIfNull(template));
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +287,7 @@ public final class Document implements Mappable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Template template() {
|
public String template() {
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +310,7 @@ public final class Document implements Mappable {
|
|||||||
map.put("taxes",positions.taxNetSums(true));
|
map.put("taxes",positions.taxNetSums(true));
|
||||||
map.put(NET_SUM, netSum());
|
map.put(NET_SUM, netSum());
|
||||||
map.put(GROSS_SUM, grossSum());
|
map.put(GROSS_SUM, grossSum());
|
||||||
if (template != null) map.put("template", template.toMap());
|
if (template != null) map.put("template", template);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
/* © SRSoftware 2025 */
|
|
||||||
package de.srsoftware.umbrella.core.model;
|
|
||||||
|
|
||||||
import static de.srsoftware.umbrella.core.Constants.*;
|
|
||||||
import static de.srsoftware.umbrella.core.Field.COMPANY;
|
|
||||||
import static de.srsoftware.umbrella.core.Field.COMPANY_ID;
|
|
||||||
|
|
||||||
import de.srsoftware.tools.Mappable;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public record Template(long id, long company, String name, byte[] data) implements Mappable {
|
|
||||||
|
|
||||||
public static Template of(ResultSet rs) throws SQLException {
|
|
||||||
return new Template(rs.getLong(ID),rs.getLong(COMPANY_ID),rs.getString(NAME),rs.getBytes(TEMPLATE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> toMap() {
|
|
||||||
return Map.of(ID,id, COMPANY,company, NAME,name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -363,7 +363,7 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Content renderDocument(Document document, UmbrellaUser user) throws UmbrellaException {
|
private Content renderDocument(Document document, UmbrellaUser user) throws UmbrellaException {
|
||||||
var template = document.template().name();
|
var template = document.template();
|
||||||
var templateName = template+".html.pdf";
|
var templateName = template+".html.pdf";
|
||||||
var type = document.type().name();
|
var type = document.type().name();
|
||||||
var zugferd = "invoice".equals(type);
|
var zugferd = "invoice".equals(type);
|
||||||
@@ -517,8 +517,10 @@ public class DocumentApi extends BaseHandler implements DocumentService {
|
|||||||
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingFieldException(COMPANY);
|
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingFieldException(COMPANY);
|
||||||
var company = companyService().get(companyId.longValue());
|
var company = companyService().get(companyId.longValue());
|
||||||
if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name());
|
if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name());
|
||||||
var templates = db.getCompanyTemplates(companyId.longValue());
|
var templates = registry.documents()
|
||||||
return sendContent(ex,templates.stream().map(Template::toMap));
|
.filter(d -> d.name().endsWith(".template"))
|
||||||
|
.map(d -> d.name().replaceAll("(\\.[^.]+)?\\.template$",""));
|
||||||
|
return sendContent(ex,templates);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException {
|
private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package de.srsoftware.umbrella.documents;
|
|||||||
import de.srsoftware.tools.Pair;
|
import de.srsoftware.tools.Pair;
|
||||||
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
|
||||||
import de.srsoftware.umbrella.core.model.Document;
|
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.core.model.Type;
|
||||||
import de.srsoftware.umbrella.documents.model.*;
|
import de.srsoftware.umbrella.documents.model.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -27,8 +26,6 @@ public interface DocumentDb {
|
|||||||
|
|
||||||
CustomerSettings getCustomerSettings(long companyId, Type docType, String customerId) throws UmbrellaException;
|
CustomerSettings getCustomerSettings(long companyId, Type docType, String customerId) throws UmbrellaException;
|
||||||
|
|
||||||
Collection<Template> getCompanyTemplates(long l) throws UmbrellaException;
|
|
||||||
|
|
||||||
Type getType(int typeId) throws UmbrellaException;
|
Type getType(int typeId) throws UmbrellaException;
|
||||||
|
|
||||||
Map<Long, Document> listDocs(long companyId) throws UmbrellaException;
|
Map<Long, Document> listDocs(long companyId) throws UmbrellaException;
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ public class SqliteDb extends BaseDb implements DocumentDb{
|
|||||||
super(connection);
|
super(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addTemplateColumn() {
|
||||||
|
try {
|
||||||
|
var sql = format("ALTER TABLE {0} ADD COLUMN {1} VARCHAR(255)",TABLE_DOCUMENTS,TEMPLATE);
|
||||||
|
db.prepareStatement(sql).execute();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw databaseException("Failed to update column {0} → {1} of {2}",TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected int createTables() {
|
protected int createTables() {
|
||||||
int currentVersion = createSettingsTable();
|
int currentVersion = createSettingsTable();
|
||||||
switch (currentVersion) {
|
switch (currentVersion) {
|
||||||
@@ -52,22 +61,15 @@ public class SqliteDb extends BaseDb implements DocumentDb{
|
|||||||
createTablePositions();
|
createTablePositions();
|
||||||
createTableCustomerPrices();
|
createTableCustomerPrices();
|
||||||
createTableCustomerSettings();
|
createTableCustomerSettings();
|
||||||
|
case 1:
|
||||||
|
addTemplateColumn();
|
||||||
|
moveTemplateNames();
|
||||||
|
dropTemplateTable();
|
||||||
|
dropTemplateIdColumn();
|
||||||
}
|
}
|
||||||
return setCurrentVersion(1);
|
return setCurrentVersion(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private void createTableCompanySettings() {
|
|
||||||
var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} INT NOT NULL, {2} INT NOT NULL, {3} TEXT DEFAULT \"A\", {4} TEXT DEFAULT NULL, {5} INT NOT NULL DEFAULT 1, PRIMARY KEY ({1}, {2}))";
|
|
||||||
try {
|
|
||||||
var stmt = db.prepareStatement(format(sql,TABLE_COMPANY_SETTINGS, COMPANY_ID,DOC_TYPE_ID,TYPE_PREFIX,TYPE_SUFFIX,TYPE_NUMBER));
|
|
||||||
stmt.execute();
|
|
||||||
stmt.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_COMPANY_SETTINGS,e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private void createTableCustomerPrices() {
|
private void createTableCustomerPrices() {
|
||||||
var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} INT NOT NULL, {2} VARCHAR(255), {3} VARCHAR(50), {4} INTEGER)";
|
var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} INT NOT NULL, {2} VARCHAR(255), {3} VARCHAR(50), {4} INTEGER)";
|
||||||
try {
|
try {
|
||||||
@@ -172,36 +174,6 @@ CREATE TABLE IF NOT EXISTS {0} (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int createTableSettings() {
|
|
||||||
var createTable = """
|
|
||||||
CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) NOT NULL);
|
|
||||||
""";
|
|
||||||
try {
|
|
||||||
var stmt = db.prepareStatement(format(createTable,TABLE_SETTINGS, KEY, VALUE));
|
|
||||||
stmt.execute();
|
|
||||||
stmt.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_SETTINGS,e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer version = null;
|
|
||||||
try {
|
|
||||||
var rs = select(VALUE).from(TABLE_SETTINGS).where(KEY, equal(DB_VERSION)).exec(db);
|
|
||||||
if (rs.next()) version = rs.getInt(VALUE);
|
|
||||||
rs.close();
|
|
||||||
if (version == null) {
|
|
||||||
version = INITIAL_DB_VERSION;
|
|
||||||
insertInto(TABLE_SETTINGS, KEY, VALUE).values(DB_VERSION,version).execute(db).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return version;
|
|
||||||
} catch (SQLException e) {
|
|
||||||
LOG.log(ERROR,ERROR_READ_TABLE,DB_VERSION,TABLE_SETTINGS,e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createTableTemplates() {
|
private void createTableTemplates() {
|
||||||
var createTable = "CREATE TABLE IF NOT EXISTS {0} ({1} INTEGER PRIMARY KEY, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} BLOB)";
|
var createTable = "CREATE TABLE IF NOT EXISTS {0} ({1} INTEGER PRIMARY KEY, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} BLOB)";
|
||||||
try {
|
try {
|
||||||
@@ -252,17 +224,21 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void dropTemplateIdColumn() {
|
||||||
public Collection<Template> getCompanyTemplates(long companyId) throws UmbrellaException {
|
|
||||||
try {
|
try {
|
||||||
|
var sql = format("ALTER TABLE {0} DROP COLUMN {1}",TABLE_DOCUMENTS,TEMPLATE_ID);
|
||||||
var rs = select(ALL).from(TABLE_TEMPLATES).where(COMPANY_ID,equal(companyId)).exec(db);
|
db.prepareStatement(sql).execute();
|
||||||
var templates = new HashSet<Template>();
|
|
||||||
while (rs.next()) templates.add(Template.of(rs));
|
|
||||||
rs.close();
|
|
||||||
return templates;
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw databaseException("Failed to load templates for company {0}",companyId);
|
throw databaseException("Failed to update column {0} → {1} of {2}",TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dropTemplateTable() {
|
||||||
|
try {
|
||||||
|
var sql = format("DROP TABLE IF EXISTS {0};",TABLE_TEMPLATES);
|
||||||
|
db.prepareStatement(sql).execute();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw databaseException("Failed to drop table {0}",TABLE_TEMPLATES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,11 +283,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
}
|
}
|
||||||
throw new UmbrellaException(500,"No type with id = {0}",typeId);
|
throw new UmbrellaException(500,"No type with id = {0}",typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
|
||||||
var version = createTables();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Long, Map<Long, String>> docReferencedByTimes(Set<Long> timeIds) throws UmbrellaException {
|
public Map<Long, Map<Long, String>> docReferencedByTimes(Set<Long> timeIds) throws UmbrellaException {
|
||||||
try {
|
try {
|
||||||
@@ -430,7 +402,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
while (rs.next()) types.put(rs.getInt(ID),toType(rs));
|
while (rs.next()) types.put(rs.getInt(ID),toType(rs));
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|
||||||
rs = Query.select(ALL).from(TABLE_DOCUMENTS).leftJoin(TEMPLATE_ID,TABLE_TEMPLATES, ID).where(TABLE_DOCUMENTS+"."+ ID,equal(docId)).exec(db);
|
rs = Query.select(ALL).from(TABLE_DOCUMENTS).where(TABLE_DOCUMENTS+"."+ ID,equal(docId)).exec(db);
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
while (rs.next()) doc = toDoc(rs,types);
|
while (rs.next()) doc = toDoc(rs,types);
|
||||||
rs.close();
|
rs.close();
|
||||||
@@ -452,6 +424,15 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
throw new UmbrellaException(500,"Failed to load document {0}.",docId);
|
throw new UmbrellaException(500,"Failed to load document {0}.",docId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void moveTemplateNames() {
|
||||||
|
try {
|
||||||
|
var sql = format("UPDATE {0} SET template = (SELECT name FROM templates WHERE templates.id = documents.template_id);",TABLE_DOCUMENTS);
|
||||||
|
db.prepareStatement(sql).execute();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw databaseException("Failed to move template.names to document.templates!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String nextDocId(String language, long companyId, Type type) {
|
public String nextDocId(String language, long companyId, Type type) {
|
||||||
try {
|
try {
|
||||||
@@ -499,9 +480,8 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
var timestamp = doc.date().atStartOfDay(UTC).toInstant().getEpochSecond();
|
var timestamp = doc.date().atStartOfDay(UTC).toInstant().getEpochSecond();
|
||||||
var sender = doc.sender();
|
var sender = doc.sender();
|
||||||
var custom = doc.customer();
|
var custom = doc.customer();
|
||||||
var templateId = doc.template() == null ? null : doc.template().id();
|
var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE,CURRENCY)
|
||||||
var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE_ID,CURRENCY)
|
.values(doc.type().id(),doc.companyId(),timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template(), doc.currency())
|
||||||
.values(doc.type().id(),doc.companyId(),timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),templateId, doc.currency())
|
|
||||||
.execute(db);
|
.execute(db);
|
||||||
var rs = stmt.getGeneratedKeys();
|
var rs = stmt.getGeneratedKeys();
|
||||||
Long newId = null;
|
Long newId = null;
|
||||||
@@ -523,10 +503,10 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
var sender = doc.sender();
|
var sender = doc.sender();
|
||||||
var custom = doc.customer();
|
var custom = doc.customer();
|
||||||
update(TABLE_DOCUMENTS)
|
update(TABLE_DOCUMENTS)
|
||||||
.set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE_ID)
|
.set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE)
|
||||||
.where(ID,equal(doc.id()))
|
.where(ID,equal(doc.id()))
|
||||||
.prepare(db)
|
.prepare(db)
|
||||||
.apply(timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template().id())
|
.apply(timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template())
|
||||||
.close();
|
.close();
|
||||||
sender.clean();
|
sender.clean();
|
||||||
custom.clean();
|
custom.clean();
|
||||||
@@ -635,23 +615,10 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
|
|||||||
var customerEmail = rs.getString(CUSTOMER_EMAIL);
|
var customerEmail = rs.getString(CUSTOMER_EMAIL);
|
||||||
var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber,FALLBACK_LANG);
|
var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber,FALLBACK_LANG);
|
||||||
var sender = new Sender(senderName,bankAccount,taxNumber,court);
|
var sender = new Sender(senderName,bankAccount,taxNumber,court);
|
||||||
var template = toTemplate(rs);
|
var template = rs.getString(TEMPLATE);
|
||||||
return new Document(id,company,number,type,date, Document.State.of(state).orElse(State.ERROR),template,delivery,head,footer,currency, DEFAULT_THOUSANDS_SEPARATOR,sender,customer,new PositionList());
|
return new Document(id,company,number,type,date, Document.State.of(state).orElse(State.ERROR),template,delivery,head,footer,currency, DEFAULT_THOUSANDS_SEPARATOR,sender,customer,new PositionList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Template toTemplate(ResultSet rs) throws SQLException {
|
|
||||||
try {
|
|
||||||
var id = rs.getLong(TEMPLATE_ID);
|
|
||||||
var company = rs.getLong(COMPANY_ID);
|
|
||||||
var name = rs.getString(NAME);
|
|
||||||
var data = rs.getBytes(TEMPLATE);
|
|
||||||
if (id == 0) return new Template(0,company,"",null);
|
|
||||||
return new Template(id,company,name,data);
|
|
||||||
} catch (SQLException ignored){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Position toPosition(ResultSet rs) throws SQLException {
|
private Position toPosition(ResultSet rs) throws SQLException {
|
||||||
var num = rs.getInt(POS);
|
var num = rs.getInt(POS);
|
||||||
var itemCode = rs.getString(ITEM_CODE);
|
var itemCode = rs.getString(ITEM_CODE);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
{#if templates}
|
{#if templates}
|
||||||
<select bind:value onchange={onchange}>
|
<select bind:value onchange={onchange}>
|
||||||
<option value={0}>{caption}</option>
|
<option value={0}>{caption}</option>
|
||||||
{#each Object.entries(templates) as [id,template]}
|
{#each templates as template}
|
||||||
<option value={template.id}>{template.name}</option>
|
<option value={template}>{template}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
@@ -214,9 +214,9 @@
|
|||||||
<th>{t('template')}:</th>
|
<th>{t('template')}:</th>
|
||||||
<td>
|
<td>
|
||||||
{#if editable}
|
{#if editable}
|
||||||
<TemplateSelector company={doc.company.id} bind:value={doc.template.id} onchange={() => update('template_id',doc.template.id)} />
|
<TemplateSelector company={doc.company.id} bind:value={doc.template} onchange={() => update('template',doc.template)} />
|
||||||
{:else}
|
{:else}
|
||||||
{doc.template.name}
|
{doc.template}
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -185,6 +185,10 @@
|
|||||||
highlight.archive = true;
|
highlight.archive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_custom(state){
|
||||||
|
return [10,20,40,60,100].includes(state);
|
||||||
|
}
|
||||||
|
|
||||||
function openTask(task_id){
|
function openTask(task_id){
|
||||||
window.open(`/task/${task_id}/view`, '_blank').focus();
|
window.open(`/task/${task_id}/view`, '_blank').focus();
|
||||||
}
|
}
|
||||||
@@ -244,7 +248,7 @@
|
|||||||
{#each users as u}
|
{#each users as u}
|
||||||
<div class="user">{u.name}</div>
|
<div class="user">{u.name}</div>
|
||||||
{#each Object.entries(project.allowed_states) as [state,name]}
|
{#each Object.entries(project.allowed_states) as [state,name]}
|
||||||
<div class={['state_'+state, highlight.user == u.id && highlight.state == state ? 'highlight':'']} ondragover={ev => hover(ev,u.id,state)} ondragleave={e => delete highlight.user} ondrop={ev => drop(u.id,state)} >
|
<div class={['state_'+state, is_custom(state) ? '':'state_custom' ,highlight.user == u.id && highlight.state == state ? 'highlight':'']} ondragover={ev => hover(ev,u.id,state)} ondragleave={e => delete highlight.user} ondrop={ev => drop(u.id,state)} >
|
||||||
{#each Object.values(tasks[u.id][state]).sort(byName) as task}
|
{#each Object.values(tasks[u.id][state]).sort(byName) as task}
|
||||||
{#if !filter || task.name.toLowerCase().includes(filter) || (task.tags && task.tags.filter(tag => tag.toLowerCase().includes(filter)).length)}
|
{#if !filter || task.name.toLowerCase().includes(filter) || (task.tags && task.tags.filter(tag => tag.toLowerCase().includes(filter)).length)}
|
||||||
<Card onclick={e => openTask(task.id)} ondragstart={ev => dragged=task} {task} tag_colors={project.tag_colors} />
|
<Card onclick={e => openTask(task.id)} ondragstart={ev => dragged=task} {task} tag_colors={project.tag_colors} />
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ tr:hover .taglist .tag button {
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.states .active{
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
.taglist .tag{
|
.taglist .tag{
|
||||||
border-color: red;
|
border-color: red;
|
||||||
}
|
}
|
||||||
@@ -186,8 +190,6 @@ tr:hover .taglist .tag button {
|
|||||||
border-color: 1px solid;
|
border-color: 1px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.warn {
|
.warn {
|
||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
color: black;
|
color: black;
|
||||||
@@ -201,6 +203,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p10 .name{
|
.task.p10 .name{
|
||||||
color: #ffa736;
|
color: #ffa736;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p10,
|
||||||
.kanban .state_20 .box.p10,
|
.kanban .state_20 .box.p10,
|
||||||
.kanban .state_40 .box.p10{
|
.kanban .state_40 .box.p10{
|
||||||
border: 5px solid #ffa736;
|
border: 5px solid #ffa736;
|
||||||
@@ -209,6 +212,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p20 .name{
|
.task.p20 .name{
|
||||||
color: #ff8f00;
|
color: #ff8f00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p20,
|
||||||
.kanban .state_20 .box.p20,
|
.kanban .state_20 .box.p20,
|
||||||
.kanban .state_40 .box.p20{
|
.kanban .state_40 .box.p20{
|
||||||
border: 5px solid #ff8f00;
|
border: 5px solid #ff8f00;
|
||||||
@@ -217,6 +221,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p30 .name{
|
.task.p30 .name{
|
||||||
color: #ff7b06;
|
color: #ff7b06;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p30,
|
||||||
.kanban .state_20 .box.p30,
|
.kanban .state_20 .box.p30,
|
||||||
.kanban .state_40 .box.p30{
|
.kanban .state_40 .box.p30{
|
||||||
border: 5px solid #ff7b06;
|
border: 5px solid #ff7b06;
|
||||||
@@ -225,6 +230,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p40 .name{
|
.task.p40 .name{
|
||||||
color: #ff6306;
|
color: #ff6306;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p40,
|
||||||
.kanban .state_20 .box.p40,
|
.kanban .state_20 .box.p40,
|
||||||
.kanban .state_40 .box.p40{
|
.kanban .state_40 .box.p40{
|
||||||
border: 5px solid #ff6306;
|
border: 5px solid #ff6306;
|
||||||
@@ -233,6 +239,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p50 .name{
|
.task.p50 .name{
|
||||||
color: #ff4c06;
|
color: #ff4c06;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p50,
|
||||||
.kanban .state_20 .box.p50,
|
.kanban .state_20 .box.p50,
|
||||||
.kanban .state_40 .box.p50{
|
.kanban .state_40 .box.p50{
|
||||||
border: 5px solid #ff4c06;
|
border: 5px solid #ff4c06;
|
||||||
@@ -241,6 +248,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p60 .name{
|
.task.p60 .name{
|
||||||
color: #ff3506;
|
color: #ff3506;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p60,
|
||||||
.kanban .state_20 .box.p60,
|
.kanban .state_20 .box.p60,
|
||||||
.kanban .state_40 .box.p60{
|
.kanban .state_40 .box.p60{
|
||||||
border: 5px solid #ff3506;
|
border: 5px solid #ff3506;
|
||||||
@@ -249,6 +257,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p70 .name{
|
.task.p70 .name{
|
||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p70,
|
||||||
.kanban .state_20 .box.p70,
|
.kanban .state_20 .box.p70,
|
||||||
.kanban .state_40 .box.p70{
|
.kanban .state_40 .box.p70{
|
||||||
border: 5px solid #ff0000;
|
border: 5px solid #ff0000;
|
||||||
@@ -257,6 +266,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p80 .name{
|
.task.p80 .name{
|
||||||
color: #df153b;
|
color: #df153b;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p80,
|
||||||
.kanban .state_20 .box.p80,
|
.kanban .state_20 .box.p80,
|
||||||
.kanban .state_40 .box.p80{
|
.kanban .state_40 .box.p80{
|
||||||
border: 5px solid #df153b;
|
border: 5px solid #df153b;
|
||||||
@@ -266,6 +276,7 @@ tr:hover .taglist .tag button {
|
|||||||
background-color: #991c34;
|
background-color: #991c34;
|
||||||
color: #ffff00;
|
color: #ffff00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p90,
|
||||||
.kanban .state_20 .box.p90,
|
.kanban .state_20 .box.p90,
|
||||||
.kanban .state_40 .box.p90{
|
.kanban .state_40 .box.p90{
|
||||||
border: 5px solid #991c34;
|
border: 5px solid #991c34;
|
||||||
@@ -275,6 +286,7 @@ tr:hover .taglist .tag button {
|
|||||||
background-color: #733440;
|
background-color: #733440;
|
||||||
color: #ffff00;
|
color: #ffff00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p100,
|
||||||
.kanban .state_20 .box.p100,
|
.kanban .state_20 .box.p100,
|
||||||
.kanban .state_40 .box.p100{
|
.kanban .state_40 .box.p100{
|
||||||
border: 5px solid #733440;
|
border: 5px solid #733440;
|
||||||
@@ -282,4 +294,4 @@ tr:hover .taglist .tag button {
|
|||||||
|
|
||||||
.vcard span.inactive{
|
.vcard span.inactive{
|
||||||
color: #222200;
|
color: #222200;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ tr:hover .taglist .tag button {
|
|||||||
background: black;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.version a.selected{
|
.version a.selected{
|
||||||
border-color: orange;
|
border-color: orange;
|
||||||
}
|
}
|
||||||
@@ -194,6 +193,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p10 .name{
|
.task.p10 .name{
|
||||||
color: #fff066;
|
color: #fff066;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p10,
|
||||||
.kanban .state_20 .box.p10,
|
.kanban .state_20 .box.p10,
|
||||||
.kanban .state_40 .box.p10{
|
.kanban .state_40 .box.p10{
|
||||||
border: 5px solid #fff066;
|
border: 5px solid #fff066;
|
||||||
@@ -202,6 +202,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p20 .name{
|
.task.p20 .name{
|
||||||
color: #ffe706;
|
color: #ffe706;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p20,
|
||||||
.kanban .state_20 .box.p20,
|
.kanban .state_20 .box.p20,
|
||||||
.kanban .state_40 .box.p20{
|
.kanban .state_40 .box.p20{
|
||||||
border: 5px solid #ffe706;
|
border: 5px solid #ffe706;
|
||||||
@@ -210,6 +211,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p30 .name{
|
.task.p30 .name{
|
||||||
color: #ffa906;
|
color: #ffa906;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p30,
|
||||||
.kanban .state_20 .box.p30,
|
.kanban .state_20 .box.p30,
|
||||||
.kanban .state_40 .box.p30{
|
.kanban .state_40 .box.p30{
|
||||||
border: 5px solid #ffa906;
|
border: 5px solid #ffa906;
|
||||||
@@ -218,6 +220,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p40 .name{
|
.task.p40 .name{
|
||||||
color: #ff8606;
|
color: #ff8606;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p40,
|
||||||
.kanban .state_20 .box.p40,
|
.kanban .state_20 .box.p40,
|
||||||
.kanban .state_40 .box.p40{
|
.kanban .state_40 .box.p40{
|
||||||
border: 5px solid #ff8606;
|
border: 5px solid #ff8606;
|
||||||
@@ -226,6 +229,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p50 .name{
|
.task.p50 .name{
|
||||||
color: #ff4c06;
|
color: #ff4c06;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p50,
|
||||||
.kanban .state_20 .box.p50,
|
.kanban .state_20 .box.p50,
|
||||||
.kanban .state_40 .box.p50{
|
.kanban .state_40 .box.p50{
|
||||||
border: 5px solid #ff4c06;
|
border: 5px solid #ff4c06;
|
||||||
@@ -234,6 +238,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p60 .name{
|
.task.p60 .name{
|
||||||
color: #ff3506;
|
color: #ff3506;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p60,
|
||||||
.kanban .state_20 .box.p60,
|
.kanban .state_20 .box.p60,
|
||||||
.kanban .state_40 .box.p60{
|
.kanban .state_40 .box.p60{
|
||||||
border: 5px solid #ff3506;
|
border: 5px solid #ff3506;
|
||||||
@@ -242,6 +247,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p70 .name{
|
.task.p70 .name{
|
||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p70,
|
||||||
.kanban .state_20 .box.p70,
|
.kanban .state_20 .box.p70,
|
||||||
.kanban .state_40 .box.p70{
|
.kanban .state_40 .box.p70{
|
||||||
border: 5px solid #ff0000;
|
border: 5px solid #ff0000;
|
||||||
@@ -250,6 +256,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p80 .name{
|
.task.p80 .name{
|
||||||
color: #df153b;
|
color: #df153b;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p80,
|
||||||
.kanban .state_20 .box.p80,
|
.kanban .state_20 .box.p80,
|
||||||
.kanban .state_40 .box.p80{
|
.kanban .state_40 .box.p80{
|
||||||
border: 5px solid #df153b;
|
border: 5px solid #df153b;
|
||||||
@@ -259,6 +266,7 @@ tr:hover .taglist .tag button {
|
|||||||
background-color: #991c34;
|
background-color: #991c34;
|
||||||
color: #ffff00;
|
color: #ffff00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p90,
|
||||||
.kanban .state_20 .box.p90,
|
.kanban .state_20 .box.p90,
|
||||||
.kanban .state_40 .box.p90{
|
.kanban .state_40 .box.p90{
|
||||||
border: 5px solid #991c34;
|
border: 5px solid #991c34;
|
||||||
@@ -268,6 +276,7 @@ tr:hover .taglist .tag button {
|
|||||||
background-color: #733440;
|
background-color: #733440;
|
||||||
color: #ffff00;
|
color: #ffff00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p100,
|
||||||
.kanban .state_20 .box.p100,
|
.kanban .state_20 .box.p100,
|
||||||
.kanban .state_40 .box.p100{
|
.kanban .state_40 .box.p100{
|
||||||
border: 5px solid #733440;
|
border: 5px solid #733440;
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ tr:hover .taglist .tag button {
|
|||||||
border-color: blue;
|
border-color: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.states .active{
|
||||||
|
background: #dfe4ff;
|
||||||
|
}
|
||||||
|
|
||||||
.taglist .tag{
|
.taglist .tag{
|
||||||
border-color: blue;
|
border-color: blue;
|
||||||
}
|
}
|
||||||
@@ -179,6 +183,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p10 .name{
|
.task.p10 .name{
|
||||||
color: #c9fbb2;
|
color: #c9fbb2;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p10,
|
||||||
.kanban .state_20 .box.p10,
|
.kanban .state_20 .box.p10,
|
||||||
.kanban .state_40 .box.p10{
|
.kanban .state_40 .box.p10{
|
||||||
border: 5px solid #c9fbb2;
|
border: 5px solid #c9fbb2;
|
||||||
@@ -187,6 +192,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p20 .name{
|
.task.p20 .name{
|
||||||
color: #cbff57;
|
color: #cbff57;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p20,
|
||||||
.kanban .state_20 .box.p20,
|
.kanban .state_20 .box.p20,
|
||||||
.kanban .state_40 .box.p20{
|
.kanban .state_40 .box.p20{
|
||||||
border: 5px solid #cbff57;
|
border: 5px solid #cbff57;
|
||||||
@@ -195,6 +201,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p30 .name{
|
.task.p30 .name{
|
||||||
color: #dfff44;
|
color: #dfff44;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p30,
|
||||||
.kanban .state_20 .box.p30,
|
.kanban .state_20 .box.p30,
|
||||||
.kanban .state_40 .box.p30{
|
.kanban .state_40 .box.p30{
|
||||||
border: 5px solid #dfff44;
|
border: 5px solid #dfff44;
|
||||||
@@ -203,6 +210,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p40 .name{
|
.task.p40 .name{
|
||||||
color: #f8ff29;
|
color: #f8ff29;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p40,
|
||||||
.kanban .state_20 .box.p40,
|
.kanban .state_20 .box.p40,
|
||||||
.kanban .state_40 .box.p40{
|
.kanban .state_40 .box.p40{
|
||||||
border: 5px solid #f8ff29;
|
border: 5px solid #f8ff29;
|
||||||
@@ -211,6 +219,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p50 .name{
|
.task.p50 .name{
|
||||||
color: #ffdb1b;
|
color: #ffdb1b;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p50,
|
||||||
.kanban .state_20 .box.p50,
|
.kanban .state_20 .box.p50,
|
||||||
.kanban .state_40 .box.p50{
|
.kanban .state_40 .box.p50{
|
||||||
border: 5px solid #ffdb1b;
|
border: 5px solid #ffdb1b;
|
||||||
@@ -219,6 +228,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p60 .name{
|
.task.p60 .name{
|
||||||
color: #ff9309;
|
color: #ff9309;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p60,
|
||||||
.kanban .state_20 .box.p60,
|
.kanban .state_20 .box.p60,
|
||||||
.kanban .state_40 .box.p60{
|
.kanban .state_40 .box.p60{
|
||||||
border: 5px solid #ff9309;
|
border: 5px solid #ff9309;
|
||||||
@@ -227,6 +237,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p70 .name{
|
.task.p70 .name{
|
||||||
color: #ff6c00;
|
color: #ff6c00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p70,
|
||||||
.kanban .state_20 .box.p70,
|
.kanban .state_20 .box.p70,
|
||||||
.kanban .state_40 .box.p70{
|
.kanban .state_40 .box.p70{
|
||||||
border: 5px solid #ff6c00;
|
border: 5px solid #ff6c00;
|
||||||
@@ -235,6 +246,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p80 .name{
|
.task.p80 .name{
|
||||||
color: #ff3c00;
|
color: #ff3c00;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p80,
|
||||||
.kanban .state_20 .box.p80,
|
.kanban .state_20 .box.p80,
|
||||||
.kanban .state_40 .box.p80{
|
.kanban .state_40 .box.p80{
|
||||||
border: 5px solid #ff3c00;
|
border: 5px solid #ff3c00;
|
||||||
@@ -243,6 +255,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p90 .name{
|
.task.p90 .name{
|
||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p90,
|
||||||
.kanban .state_20 .box.p90,
|
.kanban .state_20 .box.p90,
|
||||||
.kanban .state_40 .box.p90{
|
.kanban .state_40 .box.p90{
|
||||||
border: 5px solid #ff0000;
|
border: 5px solid #ff0000;
|
||||||
@@ -251,6 +264,7 @@ tr:hover .taglist .tag button {
|
|||||||
.task.p100 .name{
|
.task.p100 .name{
|
||||||
color: #ff0048;
|
color: #ff0048;
|
||||||
}
|
}
|
||||||
|
.kanban .state_custom .box.p100,
|
||||||
.kanban .state_20 .box.p100,
|
.kanban .state_20 .box.p100,
|
||||||
.kanban .state_40 .box.p100{
|
.kanban .state_40 .box.p100{
|
||||||
border: 5px solid #ff0048;
|
border: 5px solid #ff0048;
|
||||||
@@ -258,4 +272,4 @@ tr:hover .taglist .tag button {
|
|||||||
|
|
||||||
.vcard span.inactive{
|
.vcard span.inactive{
|
||||||
color: #bbb;
|
color: #bbb;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user