refactor: move priority emails to customer card
Priority emails are now per-customer, not per-company. Each customer can have a list of email addresses that automatically elevate ticket priority to "tärkeä" when they send email. Field added to customer form under "Lisätiedot" section. Removed separate priority_emails settings from API/rules tabs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
3
api.php
3
api.php
@@ -1198,6 +1198,7 @@ switch ($action) {
|
|||||||
'elaskuvalittaja' => trim($input['elaskuvalittaja'] ?? ''),
|
'elaskuvalittaja' => trim($input['elaskuvalittaja'] ?? ''),
|
||||||
'ytunnus' => trim($input['ytunnus'] ?? ''),
|
'ytunnus' => trim($input['ytunnus'] ?? ''),
|
||||||
'lisatiedot' => trim($input['lisatiedot'] ?? ''),
|
'lisatiedot' => trim($input['lisatiedot'] ?? ''),
|
||||||
|
'priority_emails' => trim($input['priority_emails'] ?? ''),
|
||||||
'liittymat' => parseLiittymat($input),
|
'liittymat' => parseLiittymat($input),
|
||||||
'luotu' => date('Y-m-d H:i:s'),
|
'luotu' => date('Y-m-d H:i:s'),
|
||||||
];
|
];
|
||||||
@@ -1223,7 +1224,7 @@ switch ($action) {
|
|||||||
foreach ($customers as $c) {
|
foreach ($customers as $c) {
|
||||||
if ($c['id'] === $id) {
|
if ($c['id'] === $id) {
|
||||||
$changes = [];
|
$changes = [];
|
||||||
$fields = ['yritys','yhteyshenkilö','puhelin','sahkoposti','laskutusosoite','laskutuspostinumero','laskutuskaupunki','laskutussahkoposti','elaskuosoite','elaskuvalittaja','ytunnus','lisatiedot'];
|
$fields = ['yritys','yhteyshenkilö','puhelin','sahkoposti','laskutusosoite','laskutuspostinumero','laskutuskaupunki','laskutussahkoposti','elaskuosoite','elaskuvalittaja','ytunnus','lisatiedot','priority_emails'];
|
||||||
foreach ($fields as $f) {
|
foreach ($fields as $f) {
|
||||||
if (isset($input[$f])) {
|
if (isset($input[$f])) {
|
||||||
$old = $c[$f] ?? '';
|
$old = $c[$f] ?? '';
|
||||||
|
|||||||
23
db.php
23
db.php
@@ -194,6 +194,7 @@ function initDatabase(): void {
|
|||||||
elaskuvalittaja VARCHAR(100),
|
elaskuvalittaja VARCHAR(100),
|
||||||
ytunnus VARCHAR(20),
|
ytunnus VARCHAR(20),
|
||||||
lisatiedot TEXT,
|
lisatiedot TEXT,
|
||||||
|
priority_emails TEXT DEFAULT '',
|
||||||
luotu DATETIME,
|
luotu DATETIME,
|
||||||
muokattu DATETIME NULL,
|
muokattu DATETIME NULL,
|
||||||
muokkaaja VARCHAR(100) DEFAULT '',
|
muokkaaja VARCHAR(100) DEFAULT '',
|
||||||
@@ -373,6 +374,7 @@ function initDatabase(): void {
|
|||||||
$alters = [
|
$alters = [
|
||||||
"ALTER TABLE tickets ADD COLUMN cc TEXT DEFAULT '' AFTER mailbox_id",
|
"ALTER TABLE tickets ADD COLUMN cc TEXT DEFAULT '' AFTER mailbox_id",
|
||||||
"ALTER TABLE tickets ADD COLUMN priority VARCHAR(20) DEFAULT 'normaali' AFTER cc",
|
"ALTER TABLE tickets ADD COLUMN priority VARCHAR(20) DEFAULT 'normaali' AFTER cc",
|
||||||
|
"ALTER TABLE customers ADD COLUMN priority_emails TEXT DEFAULT '' AFTER lisatiedot",
|
||||||
];
|
];
|
||||||
foreach ($alters as $sql) {
|
foreach ($alters as $sql) {
|
||||||
try { $db->query($sql); } catch (\Throwable $e) { /* sarake on jo olemassa */ }
|
try { $db->query($sql); } catch (\Throwable $e) { /* sarake on jo olemassa */ }
|
||||||
@@ -661,10 +663,10 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
_dbExecute("
|
_dbExecute("
|
||||||
INSERT INTO customers (id, company_id, yritys, yhteyshenkilö, puhelin, sahkoposti,
|
INSERT INTO customers (id, company_id, yritys, yhteyshenkilö, puhelin, sahkoposti,
|
||||||
laskutusosoite, laskutuspostinumero, laskutuskaupunki, laskutussahkoposti,
|
laskutusosoite, laskutuspostinumero, laskutuskaupunki, laskutussahkoposti,
|
||||||
elaskuosoite, elaskuvalittaja, ytunnus, lisatiedot, luotu, muokattu, muokkaaja)
|
elaskuosoite, elaskuvalittaja, ytunnus, lisatiedot, priority_emails, luotu, muokattu, muokkaaja)
|
||||||
VALUES (:id, :company_id, :yritys, :yhteyshenkilö, :puhelin, :sahkoposti,
|
VALUES (:id, :company_id, :yritys, :yhteyshenkilö, :puhelin, :sahkoposti,
|
||||||
:laskutusosoite, :laskutuspostinumero, :laskutuskaupunki, :laskutussahkoposti,
|
:laskutusosoite, :laskutuspostinumero, :laskutuskaupunki, :laskutussahkoposti,
|
||||||
:elaskuosoite, :elaskuvalittaja, :ytunnus, :lisatiedot, :luotu, :muokattu, :muokkaaja)
|
:elaskuosoite, :elaskuvalittaja, :ytunnus, :lisatiedot, :priority_emails, :luotu, :muokattu, :muokkaaja)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
yritys = VALUES(yritys), yhteyshenkilö = VALUES(yhteyshenkilö),
|
yritys = VALUES(yritys), yhteyshenkilö = VALUES(yhteyshenkilö),
|
||||||
puhelin = VALUES(puhelin), sahkoposti = VALUES(sahkoposti),
|
puhelin = VALUES(puhelin), sahkoposti = VALUES(sahkoposti),
|
||||||
@@ -672,6 +674,7 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
laskutuskaupunki = VALUES(laskutuskaupunki), laskutussahkoposti = VALUES(laskutussahkoposti),
|
laskutuskaupunki = VALUES(laskutuskaupunki), laskutussahkoposti = VALUES(laskutussahkoposti),
|
||||||
elaskuosoite = VALUES(elaskuosoite), elaskuvalittaja = VALUES(elaskuvalittaja),
|
elaskuosoite = VALUES(elaskuosoite), elaskuvalittaja = VALUES(elaskuvalittaja),
|
||||||
ytunnus = VALUES(ytunnus), lisatiedot = VALUES(lisatiedot),
|
ytunnus = VALUES(ytunnus), lisatiedot = VALUES(lisatiedot),
|
||||||
|
priority_emails = VALUES(priority_emails),
|
||||||
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
||||||
", [
|
", [
|
||||||
'id' => $customer['id'],
|
'id' => $customer['id'],
|
||||||
@@ -688,6 +691,7 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
'elaskuvalittaja' => $customer['elaskuvalittaja'] ?? '',
|
'elaskuvalittaja' => $customer['elaskuvalittaja'] ?? '',
|
||||||
'ytunnus' => $customer['ytunnus'] ?? '',
|
'ytunnus' => $customer['ytunnus'] ?? '',
|
||||||
'lisatiedot' => $customer['lisatiedot'] ?? '',
|
'lisatiedot' => $customer['lisatiedot'] ?? '',
|
||||||
|
'priority_emails' => $customer['priority_emails'] ?? '',
|
||||||
'luotu' => $customer['luotu'] ?? date('Y-m-d H:i:s'),
|
'luotu' => $customer['luotu'] ?? date('Y-m-d H:i:s'),
|
||||||
'muokattu' => $customer['muokattu'] ?? null,
|
'muokattu' => $customer['muokattu'] ?? null,
|
||||||
'muokkaaja' => $customer['muokkaaja'] ?? '',
|
'muokkaaja' => $customer['muokkaaja'] ?? '',
|
||||||
@@ -1081,15 +1085,14 @@ function dbDeleteTemplate(string $templateId): void {
|
|||||||
|
|
||||||
// ==================== PRIORITY EMAILS (ASIAKKUUDET) ====================
|
// ==================== PRIORITY EMAILS (ASIAKKUUDET) ====================
|
||||||
|
|
||||||
function dbLoadPriorityEmails(string $companyId): array {
|
|
||||||
return _dbFetchColumn("SELECT email FROM customer_priority_emails WHERE company_id = ?", [$companyId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dbIsPriorityEmail(string $companyId, string $email): bool {
|
function dbIsPriorityEmail(string $companyId, string $email): bool {
|
||||||
$email = strtolower(trim($email));
|
$email = strtolower(trim($email));
|
||||||
if (!$email) return false;
|
if (!$email) return false;
|
||||||
return (bool)_dbFetchScalar(
|
// Hae kaikki asiakkaiden priority_emails kentät ja tarkista onko sähköposti listalla
|
||||||
"SELECT COUNT(*) FROM customer_priority_emails WHERE company_id = ? AND LOWER(email) = ?",
|
$rows = _dbFetchAll("SELECT priority_emails FROM customers WHERE company_id = ? AND priority_emails != ''", [$companyId]);
|
||||||
[$companyId, $email]
|
foreach ($rows as $row) {
|
||||||
);
|
$emails = array_map('strtolower', array_map('trim', explode("\n", $row['priority_emails'])));
|
||||||
|
if (in_array($email, $emails)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
16
index.html
16
index.html
@@ -423,6 +423,7 @@
|
|||||||
<button class="btn-secondary" id="btn-cancel-rule">Peruuta</button>
|
<button class="btn-secondary" id="btn-cancel-rule">Peruuta</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -525,16 +526,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Priority-sähköpostit -->
|
|
||||||
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
|
||||||
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Priority-sähköpostiosoitteet</h3>
|
|
||||||
<p style="color:#666;font-size:0.85rem;margin-bottom:1rem;">Näiltä osoitteilta saapuvat tiketit saavat automaattisesti "Tärkeä"-prioriteetin.</p>
|
|
||||||
<textarea id="priority-emails-textarea" rows="4" style="width:100%;max-width:500px;font-family:monospace;font-size:0.85rem;" placeholder="vip@yritys.fi toimitusjohtaja@firma.fi"></textarea>
|
|
||||||
<div style="margin-top:0.5rem;">
|
|
||||||
<button class="btn-primary" id="btn-save-priority-emails">Tallenna</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Telegram-asetukset -->
|
<!-- Telegram-asetukset -->
|
||||||
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
<div class="table-card" style="padding:1.5rem;margin-top:1rem;">
|
||||||
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Telegram-hälytykset</h3>
|
<h3 style="color:#0f3460;margin-bottom:0.5rem;border-bottom:2px solid #f0f2f5;padding-bottom:0.5rem;">Telegram-hälytykset</h3>
|
||||||
@@ -766,6 +757,11 @@
|
|||||||
<div class="form-group full-width">
|
<div class="form-group full-width">
|
||||||
<textarea id="form-lisatiedot" rows="3" placeholder="Vapaamuotoiset muistiinpanot..."></textarea>
|
<textarea id="form-lisatiedot" rows="3" placeholder="Vapaamuotoiset muistiinpanot..."></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>Priority-sähköpostit</h3>
|
||||||
|
<div class="form-group full-width">
|
||||||
|
<p style="color:#888;font-size:0.82rem;margin-bottom:0.3rem;">Näiltä osoitteilta saapuvat tiketit saavat automaattisesti ⚠️ Tärkeä -prioriteetin. Yksi per rivi.</p>
|
||||||
|
<textarea id="form-priority-emails" rows="3" placeholder="vip@yritys.fi toimitusjohtaja@firma.fi" style="font-family:monospace;font-size:0.85rem;"></textarea>
|
||||||
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="submit" class="btn-primary" id="form-submit">Tallenna</button>
|
<button type="submit" class="btn-primary" id="form-submit">Tallenna</button>
|
||||||
<button type="button" class="btn-secondary" id="form-cancel">Peruuta</button>
|
<button type="button" class="btn-secondary" id="form-cancel">Peruuta</button>
|
||||||
|
|||||||
22
script.js
22
script.js
@@ -635,6 +635,7 @@ function openCustomerForm(customer = null) {
|
|||||||
document.getElementById('form-elaskuosoite').value = c ? (c.elaskuosoite || '') : '';
|
document.getElementById('form-elaskuosoite').value = c ? (c.elaskuosoite || '') : '';
|
||||||
document.getElementById('form-elaskuvalittaja').value = c ? (c.elaskuvalittaja || '') : '';
|
document.getElementById('form-elaskuvalittaja').value = c ? (c.elaskuvalittaja || '') : '';
|
||||||
document.getElementById('form-lisatiedot').value = c ? (c.lisatiedot || '') : '';
|
document.getElementById('form-lisatiedot').value = c ? (c.lisatiedot || '') : '';
|
||||||
|
document.getElementById('form-priority-emails').value = c ? (c.priority_emails || '') : '';
|
||||||
document.getElementById('form-billing-same').checked = false;
|
document.getElementById('form-billing-same').checked = false;
|
||||||
document.getElementById('billing-fields').style.display = 'block';
|
document.getElementById('billing-fields').style.display = 'block';
|
||||||
const container = document.getElementById('liittymat-container');
|
const container = document.getElementById('liittymat-container');
|
||||||
@@ -676,6 +677,7 @@ customerForm.addEventListener('submit', async (e) => {
|
|||||||
elaskuosoite: document.getElementById('form-elaskuosoite').value,
|
elaskuosoite: document.getElementById('form-elaskuosoite').value,
|
||||||
elaskuvalittaja: document.getElementById('form-elaskuvalittaja').value,
|
elaskuvalittaja: document.getElementById('form-elaskuvalittaja').value,
|
||||||
lisatiedot: document.getElementById('form-lisatiedot').value,
|
lisatiedot: document.getElementById('form-lisatiedot').value,
|
||||||
|
priority_emails: document.getElementById('form-priority-emails').value,
|
||||||
liittymat: collectLiittymatFromForm(),
|
liittymat: collectLiittymatFromForm(),
|
||||||
};
|
};
|
||||||
if (id) { data.id = id; await apiCall('customer_update', 'POST', data); }
|
if (id) { data.id = id; await apiCall('customer_update', 'POST', data); }
|
||||||
@@ -1793,8 +1795,6 @@ async function loadSettings() {
|
|||||||
|
|
||||||
// Vastauspohjat
|
// Vastauspohjat
|
||||||
loadTemplates();
|
loadTemplates();
|
||||||
// Priority emails
|
|
||||||
loadPriorityEmails();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== VASTAUSPOHJAT ====================
|
// ==================== VASTAUSPOHJAT ====================
|
||||||
@@ -1869,24 +1869,6 @@ window.deleteTemplate = async function(id) {
|
|||||||
} catch (e) { alert(e.message); }
|
} catch (e) { alert(e.message); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==================== PRIORITY EMAILS ====================
|
|
||||||
|
|
||||||
async function loadPriorityEmails() {
|
|
||||||
try {
|
|
||||||
const emails = await apiCall('priority_emails');
|
|
||||||
document.getElementById('priority-emails-textarea').value = (emails || []).join('\n');
|
|
||||||
} catch (e) { console.error(e); }
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('btn-save-priority-emails').addEventListener('click', async () => {
|
|
||||||
const text = document.getElementById('priority-emails-textarea').value;
|
|
||||||
const emails = text.split('\n').map(e => e.trim()).filter(e => e);
|
|
||||||
try {
|
|
||||||
await apiCall('priority_emails_save', 'POST', { emails });
|
|
||||||
alert('Priority-osoitteet tallennettu!');
|
|
||||||
} catch (e) { alert(e.message); }
|
|
||||||
});
|
|
||||||
|
|
||||||
// ==================== TELEGRAM ====================
|
// ==================== TELEGRAM ====================
|
||||||
|
|
||||||
document.getElementById('btn-save-telegram').addEventListener('click', async () => {
|
document.getElementById('btn-save-telegram').addEventListener('click', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user