summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLester Caine <lester@lsces.co.uk>2026-06-06 09:41:03 +0100
committerLester Caine <lester@lsces.co.uk>2026-06-06 09:41:03 +0100
commitfa31eb01f523e1c1e9eb7e4492ba8c308a98447b (patch)
treebc228d73d6bb333ee2f7178ecc3aac8ac364b157
parent17ee494db0a95e791d71261cedf0478e8a40cf4b (diff)
downloadcontact-fa31eb01f523e1c1e9eb7e4492ba8c308a98447b.tar.gz
contact-fa31eb01f523e1c1e9eb7e4492ba8c308a98447b.tar.bz2
contact-fa31eb01f523e1c1e9eb7e4492ba8c308a98447b.zip
xref item templates: drop dead Link/nbsp column; move generics to liberty
- view_xref_address_item.tpl, view_xref_phone_item.tpl: remove &nbsp; second column - view_xref_contact_group.tpl: add 30/30/40% widths to Type/Value/Note - view_xref_text_item.tpl, list_xref_generic.tpl: deleted — fall through to liberty equivalents - ImportContactCSV.php: set xorder explicitly (#P/#F → 1, others → 0) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--import/ImportContactCSV.php123
-rwxr-xr-xtemplates/list_xref_generic.tpl50
-rwxr-xr-xtemplates/view_xref_address_item.tpl23
-rw-r--r--templates/view_xref_contact_group.tpl35
-rwxr-xr-xtemplates/view_xref_phone_item.tpl19
-rwxr-xr-xtemplates/view_xref_text_item.tpl52
6 files changed, 176 insertions, 126 deletions
diff --git a/import/ImportContactCSV.php b/import/ImportContactCSV.php
new file mode 100644
index 0000000..b12fff9
--- /dev/null
+++ b/import/ImportContactCSV.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Contact CSV importer — matches the export_contacts.php column layout.
+ *
+ * CSV column layout (0-based, header row skipped by loader):
+ * 0 title Contact name — match key (lc.title)
+ * 1 type xref item code: $00 (person), $01–$05 (business types)
+ * 2 person_name Pipe-separated name for $00: prefix|forename|surname|suffix
+ * 3 scref SCREF xkey (stock source reference / short code)
+ * 4 phone #P xkey
+ * 5 address #C xkey_ext (full address text)
+ * 6 postcode #C xkey
+ * 7 fax #F xkey
+ * 8 website #W xkey_ext (URLs exceed xkey C(32))
+ * 9 email #E xkey_ext (addresses exceed xkey C(32))
+ * 10 accno ACCNO xkey
+ *
+ * Existing contacts (matched by title) are updated in place.
+ * New contacts are created via Contact::store() — liberty handles all required fields.
+ *
+ * @package contact
+ */
+
+namespace Bitweaver\Liberty;
+
+use Bitweaver\Contact\Contact;
+
+function contactCsvUpsertXref( int $contentId, string $item, string $xkey = '', string $xkeyExt = '', int $xorder = 0 ): void {
+ global $gBitDb;
+ $gBitDb->query(
+ "DELETE FROM `" . BIT_DB_PREFIX . "liberty_xref` WHERE `content_id` = ? AND `item` = ?",
+ [ $contentId, $item ]
+ );
+ if( $xkey !== '' || $xkeyExt !== '' ) {
+ $gBitDb->associateInsert( BIT_DB_PREFIX . 'liberty_xref', [
+ 'xref_id' => $gBitDb->GenID( 'liberty_xref_seq' ),
+ 'content_id' => $contentId,
+ 'item' => $item,
+ 'xorder' => $xorder,
+ 'xkey' => $xkey !== '' ? substr( $xkey, 0, 32 ) : null,
+ 'xkey_ext' => $xkeyExt !== '' ? substr( $xkeyExt, 0, 250 ) : null,
+ 'last_update_date' => $gBitDb->NOW(),
+ ] );
+ }
+}
+
+function contactCsvImportRow( array $row, int $rowNum ): array {
+ global $gBitDb;
+
+ $result = [ 'loaded' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => [] ];
+
+ $title = trim( $row[0] ?? '' );
+ $type = trim( $row[1] ?? '' );
+ $personName = trim( $row[2] ?? '' );
+ $scref = trim( $row[3] ?? '' );
+ $phone = trim( $row[4] ?? '' );
+ // Restore leading zero stripped by Excel on 10-digit UK numbers
+ if( strlen( $phone ) === 10 && ctype_digit( $phone ) ) {
+ $phone = '0' . $phone;
+ }
+ $address = trim( $row[5] ?? '' );
+ $postcode = trim( $row[6] ?? '' );
+ $fax = trim( $row[7] ?? '' );
+ if( strlen( $fax ) === 10 && ctype_digit( $fax ) ) {
+ $fax = '0' . $fax;
+ }
+ $website = trim( $row[8] ?? '' );
+ $email = trim( $row[9] ?? '' );
+ $accno = trim( $row[10] ?? '' );
+
+ if( empty( $title ) ) {
+ $result['skipped']++;
+ return $result;
+ }
+
+ // --- Find existing or create new via Contact class ---
+ $contentId = $gBitDb->getOne(
+ "SELECT `content_id` FROM `" . BIT_DB_PREFIX . "liberty_content`
+ WHERE `content_type_guid` = 'contact' AND `title` = ?",
+ [ $title ]
+ );
+
+ $contact = new Contact( null, $contentId ?: null );
+ if( $contentId ) {
+ $contact->load();
+ }
+
+ $pHash = [
+ 'title' => $title,
+ 'edit' => '',
+ 'format_guid' => 'bithtml',
+ ];
+ if( $contentId ) {
+ $pHash['content_id'] = $contentId;
+ }
+
+ if( !empty( $type ) && $type[0] === '$' ) {
+ $pHash['contact_types'] = [ $type ];
+ if( $type === '$00' ) {
+ $pHash['name'] = $personName;
+ }
+ }
+
+ if( !$contact->store( $pHash ) ) {
+ $result['skipped']++;
+ $result['errors'][] = "Row $rowNum: failed to store '$title': " . implode( ', ', $contact->mErrors ?? [] );
+ return $result;
+ }
+
+ $contentId ? $result['updated']++ : $result['loaded']++;
+ $contentId = $contact->mContentId;
+
+ // --- Remaining xref items ---
+ contactCsvUpsertXref( $contentId, 'SCREF', $scref );
+ contactCsvUpsertXref( $contentId, '#P', $phone, '', 1 );
+ contactCsvUpsertXref( $contentId, '#C', $postcode, $address );
+ contactCsvUpsertXref( $contentId, '#F', $fax, '', 1 );
+ contactCsvUpsertXref( $contentId, '#W', '', $website );
+ contactCsvUpsertXref( $contentId, '#E', '', $email );
+ contactCsvUpsertXref( $contentId, 'ACCNO', $accno );
+
+ return $result;
+}
diff --git a/templates/list_xref_generic.tpl b/templates/list_xref_generic.tpl
deleted file mode 100755
index aeeff7c..0000000
--- a/templates/list_xref_generic.tpl
+++ /dev/null
@@ -1,50 +0,0 @@
-{* if isset( $gContent->mInfo.$source ) *}
- {assign var=xrefcnt value=$gContent->mInfo.$source|default:[]|@count}
- {jstab title="$source_title ($xrefcnt)"}
- {legend legend=$source_title}
- <div class="form-group table-responsive">
- <table>
- <thead>
- <tr>
- <th>ID</th>
- <th>Link</th>
- <th>Data</th>
- <th>Note</th>
- {if $source ne 'history' }
- <th>Started</th>
- {else}
- <th>Ended</th>
- {/if}
- </td>
- {if $gBitSystem->isFeatureActive( 'contact_list_last_modified' )}
- <th>Updated</th>
- {/if}
- <th>Edit</th>
- </tr>
- </thead>
- <tbody>
- {section name=xref loop=$gContent->mInfo.$source}
- {assign var=_rowTpl value=$gContent->mInfo.$source[xref].template}
- <tr class="{cycle values="even,odd"}" title="{$gContent->mInfo.title|escape}">
- {include file=$gContent->getXrefRecordTemplate($_rowTpl)}
- </tr>
- {sectionelse}
- <tr class="norecords">
- <td colspan="3">
- {tr}No {$source} records found{/tr}
- </td>
- </tr>
- {/section}
- </tbody>
- </table>
- </div>
- {if $gBitUser->hasPermission('p_contact_update')}
- <div>
- {if $source ne 'history' }
- {smartlink ititle="Add additional detail record" ifile="add_xref.php" biticon="list-add" content_id=$gContent->mInfo.content_id group=$group}
- {/if}
- </div>
- {/if}
- {/legend}
- {/jstab}
-{* /if *}
diff --git a/templates/view_xref_address_item.tpl b/templates/view_xref_address_item.tpl
index 0695731..368aef6 100755
--- a/templates/view_xref_address_item.tpl
+++ b/templates/view_xref_address_item.tpl
@@ -1,22 +1,19 @@
{strip}
<td>
- {$gContent->mInfo.$source[xref].source_title|escape}
+ {$xrefInfo.xref_title|escape}
</td>
<td>
-&nbsp;
+ {$xrefInfo.xkey_ext|escape}{if $xrefInfo.address}, {$xrefInfo.address|escape}{/if}{if $xrefInfo.xkey}, {$xrefInfo.xkey|escape}{/if}
</td>
<td>
- {$gContent->mInfo.$source[xref].xkey_ext|escape}, {$gContent->mInfo.$source[xref].address|escape}, {$gContent->mInfo.$source[xref].xkey|escape}
-</td>
-<td>
- {$gContent->mInfo.$source[xref].data|escape}
+ {$xrefInfo.data|escape}
</td>
{if $xrefAllowEdit}
<td>
{if $source ne 'history' }
- {$gContent->mInfo.$source[xref].start_date|bit_short_date}
+ {$xrefInfo.start_date|bit_short_date}
{else}
- {$gContent->mInfo.$source[xref].end_date|bit_short_date}
+ {$xrefInfo.end_date|bit_short_date}
{/if}
</td>
{if $gBitSystem->isFeatureActive( 'contact_list_last_modified' )}
@@ -27,16 +24,16 @@
<td>
<span class="actionicon">
{if $gBitUser->hasPermission( 'p_contact_view_detail' )}
- {smartlink ititle="View" ifile="view_xref.php" biticon="view-fullscreen" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
+ {smartlink ititle="View" ifile="view_xref.php" biticon="view-fullscreen" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id}
{/if}
{if $gBitUser->hasPermission( 'p_contact_update' ) && $source ne 'history' }
- {smartlink ititle="Edit" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
+ {smartlink ititle="Edit" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id}
{/if}
- {if $gBitUser->hasPermission( 'p_contact_expunge' ) && $gContent->mInfo.$source[xref].item ne 'KEY_B' }
+ {if $gBitUser->hasPermission( 'p_contact_expunge' ) && $xrefInfo.item ne 'KEY_B' }
{if $source eq 'history' }
- {smartlink ititle="Restore" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=-1}
+ {smartlink ititle="Restore" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id expunge=-1}
{else}
- {smartlink ititle="Delete" ifile="edit_xref.php" biticon="user-trash" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=1}
+ {smartlink ititle="Delete" ifile="edit_xref.php" biticon="user-trash" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id expunge=1}
{/if}
{/if}
</span>
diff --git a/templates/view_xref_contact_group.tpl b/templates/view_xref_contact_group.tpl
new file mode 100644
index 0000000..cada284
--- /dev/null
+++ b/templates/view_xref_contact_group.tpl
@@ -0,0 +1,35 @@
+{assign var=xrefAllowEdit value=$allow_edit|default:true}
+{jstab title="`$xrefGroup->mTitle` ({$xrefGroup->mXrefs|@count})"}
+{legend legend=$xrefGroup->mTitle}
+<div class="form-group table-responsive">
+ <table>
+ <thead>
+ <tr>
+ <th style="width:30%">{tr}Type{/tr}</th>
+ <th style="width:30%">{tr}Value{/tr}</th>
+ <th style="width:40%">{tr}Note{/tr}</th>
+ {if $xrefAllowEdit}<th>{tr}Added{/tr}</th><th>{tr}Edit{/tr}</th>{/if}
+ </tr>
+ </thead>
+ <tbody>
+ {if $xrefGroup->mXrefs}
+ {foreach $xrefGroup->mXrefs as $xrefInfo}
+ <tr class="{cycle values="even,odd"}">
+ {include file=$gContent->getXrefRecordTemplate($xrefInfo.template)}
+ </tr>
+ {/foreach}
+ {else}
+ <tr class="norecords">
+ <td colspan="{if $xrefAllowEdit}5{else}3{/if}">{tr}No {$xrefGroup->mTitle} records found{/tr}</td>
+ </tr>
+ {/if}
+ </tbody>
+ </table>
+</div>
+{if $allow_add && $gContent->isValid() && $gContent->hasUpdatePermission() && $xrefGroup->mXGroup ne 'history'}
+ <div>
+ {smartlink ititle="Add record" ipackage="liberty" ifile="add_xref.php" biticon="list-add" content_id=$gContent->mInfo.content_id group=$xrefGroup->mSortOrder}
+ </div>
+{/if}
+{/legend}
+{/jstab}
diff --git a/templates/view_xref_phone_item.tpl b/templates/view_xref_phone_item.tpl
index 8e9bc3c..751948f 100755
--- a/templates/view_xref_phone_item.tpl
+++ b/templates/view_xref_phone_item.tpl
@@ -1,22 +1,19 @@
{strip}
<td>
- {$gContent->mInfo.$source[xref].source_title|escape}
+ {$xrefInfo.xref_title|escape}
</td>
<td>
-&nbsp;
+ {$xrefInfo.xkey|escape}
</td>
<td>
- {$gContent->mInfo.$source[xref].xkey|escape}
-</td>
-<td>
- {$gContent->mInfo.$source[xref].data|escape}
+ {$xrefInfo.data|escape}
</td>
{if $xrefAllowEdit}
<td>
{if $source ne 'history' }
- {$gContent->mInfo.$source[xref].start_date|bit_short_date}
+ {$xrefInfo.start_date|bit_short_date}
{else}
- {$gContent->mInfo.$source[xref].end_date|bit_short_date}
+ {$xrefInfo.end_date|bit_short_date}
{/if}
</td>
{if $gBitSystem->isFeatureActive( 'contact_list_last_modified' )}
@@ -27,13 +24,13 @@
<td>
<span class="actionicon">
{if $gBitUser->hasPermission( 'p_contact_update' ) && $source ne 'history' }
- {smartlink ititle="Edit" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
+ {smartlink ititle="Edit" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id}
{/if}
{if $gBitUser->hasPermission( 'p_contact_expunge' ) }
{if $source eq 'history' }
- {smartlink ititle="Restore" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=-1}
+ {smartlink ititle="Restore" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id expunge=-1}
{else}
- {smartlink ititle="Delete" ifile="edit_xref.php" biticon="user-trash" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=1}
+ {smartlink ititle="Delete" ifile="edit_xref.php" biticon="user-trash" content_id=$gContent->mInfo.content_id xref_id=$xrefInfo.xref_id expunge=1}
{/if}
{/if}
</span>
diff --git a/templates/view_xref_text_item.tpl b/templates/view_xref_text_item.tpl
deleted file mode 100755
index e24895a..0000000
--- a/templates/view_xref_text_item.tpl
+++ /dev/null
@@ -1,52 +0,0 @@
-{strip}
-<td>
- {$gContent->mInfo.$source[xref].source_title|escape}
-</td>
-<td>
- {if isset($gContent->mInfo.$source[xref].xref) && $gContent->mInfo.$source[xref].xref <> '' && $gContent->mInfo.$source[xref].xref > 100 }
- {$gContent->mInfo.$source[xref].xref|escape}
- {smartlink ititle="Link to" ifile="display_contact.php" biticon="edit" content_id=$gContent->mInfo.$source[xref].xref}
- {else}
- &nbsp;
- {/if}
-</td>
-<td>
- {$gContent->mInfo.$source[xref].xkey|escape} {$gContent->mInfo.$source[xref].xkey_ext|escape}
-</td>
-<td>
- {$gContent->mInfo.$source[xref].data|escape}
-</td>
-{if $xrefAllowEdit}
-<td>
-{if $source ne 'history' }
- {$gContent->mInfo.$source[xref].start_date|bit_short_date}
-{else}
- {$gContent->mInfo.$source[xref].end_date|bit_short_date}
-{/if}
-</td>
-{if $gBitSystem->isFeatureActive( 'contact_list_last_modified' )}
- <td>
- {$gContent->mInfo.xref[xref].last_update_date|bit_long_date}
- </td>
-{/if}
-<td>
- <span class="actionicon">
- {if $gBitUser->hasPermission( 'p_contact_update' ) && $source ne 'history' }
- {if $gContent->mInfo.$source[xref].item eq 'KEY_B' }
- {smartlink ititle="Callout" ifile="edit_key_break.php" biticon="edit-redo" expunge=0 content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
- {smartlink ititle="Reseal" ifile="edit_key_break.php" biticon="edit-undo" expunge=2 content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
- {else}
- {smartlink ititle="Edit" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id}
- {/if}
- {/if}
- {if $gBitUser->hasPermission( 'p_contact_expunge' ) && $gContent->mInfo.$source[xref].item ne 'KEY_B' }
- {if $source eq 'history' }
- {smartlink ititle="Restore" ifile="edit_xref.php" biticon="edit" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=-1}
- {else}
- {smartlink ititle="Delete" ifile="edit_xref.php" biticon="user-trash" content_id=$gContent->mInfo.content_id xref_id=$gContent->mInfo.$source[xref].xref_id expunge=1}
- {/if}
- {/if}
- </span>
-</td>
-{/if}
-{/strip}