Files
WooDoo/includes/class-woodoo-admin.php

403 lines
20 KiB
PHP
Raw Normal View History

<?php
/**
* Admin: settings page, customer linking, connection test.
*/
defined( 'ABSPATH' ) || exit;
class WooDoo_Admin {
public static function init(): void {
add_action( 'admin_menu', [ __CLASS__, 'add_menu' ] );
add_action( 'admin_init', [ __CLASS__, 'register_settings' ] );
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_admin_assets' ] );
// User profile: add Odoo Partner ID field
add_action( 'show_user_profile', [ __CLASS__, 'user_profile_fields' ] );
add_action( 'edit_user_profile', [ __CLASS__, 'user_profile_fields' ] );
add_action( 'personal_options_update',[ __CLASS__, 'save_user_profile_fields' ] );
add_action( 'edit_user_profile_update',[ __CLASS__, 'save_user_profile_fields' ] );
// AJAX handlers (admin only)
add_action( 'wp_ajax_woodoo_test_connection', [ __CLASS__, 'ajax_test_connection' ] );
add_action( 'wp_ajax_woodoo_search_partners', [ __CLASS__, 'ajax_search_partners' ] );
add_action( 'wp_ajax_woodoo_link_customer', [ __CLASS__, 'ajax_link_customer' ] );
// WC customer list column
add_filter( 'manage_users_columns', [ __CLASS__, 'add_users_column' ] );
add_filter( 'manage_users_custom_column', [ __CLASS__, 'render_users_column' ], 10, 3 );
}
// ── Menu & Settings ───────────────────────────────────────────────────
public static function add_menu(): void {
add_submenu_page(
'woocommerce',
__( 'WooDoo Odoo Integration', 'woodoo' ),
__( 'Odoo Integration', 'woodoo' ),
'manage_woocommerce',
'woodoo-settings',
[ __CLASS__, 'render_settings_page' ]
);
}
public static function register_settings(): void {
$fields = [
'woodoo_odoo_url' => __( 'Odoo URL (e.g. https://odoo.example.com)', 'woodoo' ),
'woodoo_odoo_db' => __( 'Database Name', 'woodoo' ),
'woodoo_odoo_username' => __( 'Username / Login', 'woodoo' ),
'woodoo_odoo_api_key' => __( 'API Key', 'woodoo' ),
];
foreach ( $fields as $key => $label ) {
register_setting( 'woodoo_settings', $key, [ 'sanitize_callback' => 'sanitize_text_field' ] );
}
// Meeting settings
$meeting_fields = [
'woodoo_meeting_duration' => 30, // minutes
'woodoo_available_days' => [ 1, 2, 3, 4, 5 ], // Mon-Fri
'woodoo_available_from' => '09:00',
'woodoo_available_to' => '17:00',
'woodoo_meeting_title_prefix'=> 'Meeting via WooDoo',
];
foreach ( $meeting_fields as $key => $default ) {
register_setting( 'woodoo_settings', $key );
}
// Order sync toggle
register_setting( 'woodoo_settings', 'woodoo_sync_orders', [ 'sanitize_callback' => 'rest_sanitize_boolean' ] );
}
public static function enqueue_admin_assets( string $hook ): void {
if ( strpos( $hook, 'woodoo-settings' ) === false
&& $hook !== 'user-edit.php'
&& $hook !== 'profile.php' ) {
return;
}
wp_enqueue_style(
'woodoo-admin',
WOODOO_URL . 'assets/css/woodoo-admin.css',
[],
WOODOO_VERSION
);
wp_enqueue_script(
'woodoo-admin',
WOODOO_URL . 'assets/js/woodoo-admin.js',
[ 'jquery' ],
WOODOO_VERSION,
true
);
wp_localize_script( 'woodoo-admin', 'WooDooAdmin', [
'nonce' => wp_create_nonce( 'woodoo_admin' ),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'i18n' => [
'testing' => __( 'Testing…', 'woodoo' ),
'searching' => __( 'Searching…', 'woodoo' ),
'link_done' => __( 'Linked!', 'woodoo' ),
'error' => __( 'Error. Check console.', 'woodoo' ),
],
] );
}
// ── Settings Page HTML ────────────────────────────────────────────────
public static function render_settings_page(): void {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( esc_html__( 'Access denied.', 'woodoo' ) );
}
$days_map = [
1 => __( 'Monday', 'woodoo' ),
2 => __( 'Tuesday', 'woodoo' ),
3 => __( 'Wednesday', 'woodoo' ),
4 => __( 'Thursday', 'woodoo' ),
5 => __( 'Friday', 'woodoo' ),
6 => __( 'Saturday', 'woodoo' ),
7 => __( 'Sunday', 'woodoo' ),
];
$saved_days = (array) get_option( 'woodoo_available_days', [ 1, 2, 3, 4, 5 ] );
?>
<div class="wrap woodoo-settings">
<h1><?php esc_html_e( 'WooDoo Odoo Integration', 'woodoo' ); ?></h1>
<nav class="nav-tab-wrapper">
<a href="#tab-connection" class="nav-tab nav-tab-active"><?php esc_html_e( 'Connection', 'woodoo' ); ?></a>
<a href="#tab-meetings" class="nav-tab"><?php esc_html_e( 'Meetings', 'woodoo' ); ?></a>
<a href="#tab-orders" class="nav-tab"><?php esc_html_e( 'Order Sync', 'woodoo' ); ?></a>
<a href="#tab-customers" class="nav-tab"><?php esc_html_e( 'Customers', 'woodoo' ); ?></a>
</nav>
<form method="post" action="options.php">
<?php settings_fields( 'woodoo_settings' ); ?>
<!-- Connection Tab -->
<div id="tab-connection" class="woodoo-tab active">
<h2><?php esc_html_e( 'Odoo Connection', 'woodoo' ); ?></h2>
<table class="form-table">
<tr>
<th><?php esc_html_e( 'Odoo URL', 'woodoo' ); ?></th>
<td>
<input type="url" name="woodoo_odoo_url" value="<?php echo esc_attr( get_option( 'woodoo_odoo_url' ) ); ?>" class="regular-text" placeholder="https://odoo.yourcompany.com">
<p class="description"><?php esc_html_e( 'Include https://, no trailing slash.', 'woodoo' ); ?></p>
</td>
</tr>
<tr>
<th><?php esc_html_e( 'Database Name', 'woodoo' ); ?></th>
<td><input type="text" name="woodoo_odoo_db" value="<?php echo esc_attr( get_option( 'woodoo_odoo_db' ) ); ?>" class="regular-text"></td>
</tr>
<tr>
<th><?php esc_html_e( 'Username', 'woodoo' ); ?></th>
<td><input type="text" name="woodoo_odoo_username" value="<?php echo esc_attr( get_option( 'woodoo_odoo_username' ) ); ?>" class="regular-text" autocomplete="off"></td>
</tr>
<tr>
<th><?php esc_html_e( 'API Key', 'woodoo' ); ?></th>
<td>
<input type="password" name="woodoo_odoo_api_key" value="<?php echo esc_attr( get_option( 'woodoo_odoo_api_key' ) ); ?>" class="regular-text" autocomplete="off">
<p class="description"><?php esc_html_e( 'Generate in Odoo: Settings → Users → Your User → Account Security → New API Key.', 'woodoo' ); ?></p>
</td>
</tr>
</table>
<p>
<button type="button" id="woodoo-test-connection" class="button button-secondary">
<?php esc_html_e( 'Test Connection', 'woodoo' ); ?>
</button>
<span id="woodoo-test-result" style="margin-left:12px;"></span>
</p>
</div>
<!-- Meetings Tab -->
<div id="tab-meetings" class="woodoo-tab" style="display:none;">
<h2><?php esc_html_e( 'Meeting / Booking Settings', 'woodoo' ); ?></h2>
<table class="form-table">
<tr>
<th><?php esc_html_e( 'Slot Duration (minutes)', 'woodoo' ); ?></th>
<td>
<input type="number" name="woodoo_meeting_duration" value="<?php echo esc_attr( get_option( 'woodoo_meeting_duration', 30 ) ); ?>" min="15" max="240" step="15" class="small-text">
</td>
</tr>
<tr>
<th><?php esc_html_e( 'Available Days', 'woodoo' ); ?></th>
<td>
<?php foreach ( $days_map as $num => $label ) : ?>
<label style="margin-right:12px;">
<input type="checkbox" name="woodoo_available_days[]" value="<?php echo esc_attr( $num ); ?>"
<?php checked( in_array( $num, $saved_days, true ) ); ?>>
<?php echo esc_html( $label ); ?>
</label>
<?php endforeach; ?>
</td>
</tr>
<tr>
<th><?php esc_html_e( 'Available From', 'woodoo' ); ?></th>
<td><input type="time" name="woodoo_available_from" value="<?php echo esc_attr( get_option( 'woodoo_available_from', '09:00' ) ); ?>"></td>
</tr>
<tr>
<th><?php esc_html_e( 'Available To', 'woodoo' ); ?></th>
<td><input type="time" name="woodoo_available_to" value="<?php echo esc_attr( get_option( 'woodoo_available_to', '17:00' ) ); ?>"></td>
</tr>
<tr>
<th><?php esc_html_e( 'Meeting Title Prefix', 'woodoo' ); ?></th>
<td><input type="text" name="woodoo_meeting_title_prefix" value="<?php echo esc_attr( get_option( 'woodoo_meeting_title_prefix', 'Meeting via WooDoo' ) ); ?>" class="regular-text"></td>
</tr>
</table>
</div>
<!-- Order Sync Tab -->
<div id="tab-orders" class="woodoo-tab" style="display:none;">
<h2><?php esc_html_e( 'Order → Odoo Sales Order Sync', 'woodoo' ); ?></h2>
<table class="form-table">
<tr>
<th><?php esc_html_e( 'Enable Order Sync', 'woodoo' ); ?></th>
<td>
<label>
<input type="checkbox" name="woodoo_sync_orders" value="1" <?php checked( get_option( 'woodoo_sync_orders', 1 ) ); ?>>
<?php esc_html_e( 'Automatically create a Sales Order in Odoo when a WooCommerce order is placed (status: processing).', 'woodoo' ); ?>
</label>
</td>
</tr>
</table>
<div class="woodoo-info-box">
<strong><?php esc_html_e( 'How it works:', 'woodoo' ); ?></strong>
<ul>
<li><?php esc_html_e( 'When a WooCommerce order reaches "Processing" status, WooDoo finds or creates the customer in Odoo.', 'woodoo' ); ?></li>
<li><?php esc_html_e( 'Products are matched by SKU (default_code). Unmatched items are added as generic lines.', 'woodoo' ); ?></li>
<li><?php esc_html_e( 'The Odoo Sales Order is left in "Quotation" (draft) state, ready for invoicing.', 'woodoo' ); ?></li>
<li><?php esc_html_e( 'The Odoo SO reference is saved as order meta and visible in the WC order screen.', 'woodoo' ); ?></li>
</ul>
</div>
</div>
<!-- Customer Linking Tab -->
<div id="tab-customers" class="woodoo-tab" style="display:none;">
<h2><?php esc_html_e( 'Customer Linking', 'woodoo' ); ?></h2>
<p><?php esc_html_e( 'Link WooCommerce customers to their Odoo partner record. You can also edit this from each user\'s profile page.', 'woodoo' ); ?></p>
<div class="woodoo-customer-linker">
<label><?php esc_html_e( 'Search WooCommerce Customer:', 'woodoo' ); ?></label>
<input type="text" id="woo-customer-search" class="regular-text" placeholder="<?php esc_attr_e( 'Customer name or email…', 'woodoo' ); ?>">
<div id="woo-customer-results"></div>
</div>
</div>
<?php submit_button(); ?>
</form>
</div>
<?php
}
// ── User Profile Fields ───────────────────────────────────────────────
public static function user_profile_fields( WP_User $user ): void {
if ( ! current_user_can( 'edit_users' ) ) return;
$partner_id = get_user_meta( $user->ID, 'woodoo_odoo_partner_id', true );
$partner_name = get_user_meta( $user->ID, 'woodoo_odoo_partner_name', true );
?>
<h2><?php esc_html_e( 'Odoo Integration (WooDoo)', 'woodoo' ); ?></h2>
<table class="form-table">
<tr>
<th><?php esc_html_e( 'Odoo Partner ID', 'woodoo' ); ?></th>
<td>
<input type="number" id="woodoo_odoo_partner_id" name="woodoo_odoo_partner_id"
value="<?php echo esc_attr( $partner_id ); ?>"
class="small-text" min="1">
<?php if ( $partner_name ) : ?>
<span id="woodoo-partner-name-display" style="margin-left:8px;color:#666;">
<?php echo esc_html( $partner_name ); ?>
</span>
<?php endif; ?>
<p class="description">
<?php esc_html_e( 'Leave blank to auto-match by email on next sync. Or type an ID and the name will resolve automatically.', 'woodoo' ); ?>
</p>
<input type="hidden" name="woodoo_nonce" value="<?php echo esc_attr( wp_create_nonce( 'woodoo_user_profile_' . $user->ID ) ); ?>">
<p>
<strong><?php esc_html_e( 'Search Odoo partners:', 'woodoo' ); ?></strong><br>
<input type="text" id="woodoo-partner-search-input" class="regular-text"
placeholder="<?php esc_attr_e( 'Name or email…', 'woodoo' ); ?>"
data-user-id="<?php echo esc_attr( $user->ID ); ?>">
<button type="button" id="woodoo-partner-search-btn" class="button button-secondary" style="margin-left:4px;">
<?php esc_html_e( 'Search', 'woodoo' ); ?>
</button>
<div id="woodoo-partner-search-results" style="margin-top:8px;"></div>
</p>
</td>
</tr>
<?php
$odoo_so_count = get_user_meta( $user->ID, 'woodoo_so_count', true );
if ( $odoo_so_count ) : ?>
<tr>
<th><?php esc_html_e( 'Odoo Sales Orders', 'woodoo' ); ?></th>
<td>
<span><?php echo esc_html( $odoo_so_count ); ?> <?php esc_html_e( 'orders synced to Odoo', 'woodoo' ); ?></span>
</td>
</tr>
<?php endif; ?>
</table>
<?php
}
public static function save_user_profile_fields( int $user_id ): void {
if ( ! isset( $_POST['woodoo_nonce'] )
|| ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['woodoo_nonce'] ) ), 'woodoo_user_profile_' . $user_id )
) {
return;
}
if ( ! current_user_can( 'edit_user', $user_id ) ) return;
$partner_id = isset( $_POST['woodoo_odoo_partner_id'] )
? absint( $_POST['woodoo_odoo_partner_id'] )
: 0;
if ( $partner_id > 0 ) {
update_user_meta( $user_id, 'woodoo_odoo_partner_id', $partner_id );
// Resolve name from Odoo
$api = woodoo_api();
if ( $api ) {
$partners = $api->read( 'res.partner', [ $partner_id ], [ 'name', 'email' ] );
if ( ! empty( $partners[0]['name'] ) ) {
update_user_meta( $user_id, 'woodoo_odoo_partner_name', sanitize_text_field( $partners[0]['name'] ) );
}
}
} else {
delete_user_meta( $user_id, 'woodoo_odoo_partner_id' );
delete_user_meta( $user_id, 'woodoo_odoo_partner_name' );
}
}
// ── Users List Column ─────────────────────────────────────────────────
public static function add_users_column( array $columns ): array {
$columns['woodoo_odoo'] = __( 'Odoo Partner', 'woodoo' );
return $columns;
}
public static function render_users_column( string $value, string $column, int $user_id ): string {
if ( $column !== 'woodoo_odoo' ) return $value;
$partner_id = get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
$partner_name = get_user_meta( $user_id, 'woodoo_odoo_partner_name', true );
if ( $partner_id ) {
return '<span style="color:#2271b1;">' . esc_html( $partner_name ?: "#$partner_id" ) . '</span>';
}
return '<span style="color:#999;">—</span>';
}
// ── AJAX Handlers ─────────────────────────────────────────────────────
public static function ajax_test_connection(): void {
check_ajax_referer( 'woodoo_admin', 'nonce' );
if ( ! current_user_can( 'manage_woocommerce' ) ) wp_send_json_error( 'Forbidden', 403 );
$api = woodoo_api();
if ( ! $api ) {
wp_send_json_error( 'Credentials not saved yet. Save settings first.' );
}
wp_send_json_success( $api->test_connection() );
}
public static function ajax_search_partners(): void {
check_ajax_referer( 'woodoo_admin', 'nonce' );
if ( ! current_user_can( 'edit_users' ) ) wp_send_json_error( 'Forbidden', 403 );
$q = sanitize_text_field( wp_unslash( $_POST['query'] ?? '' ) );
$api = woodoo_api();
if ( ! $api || empty( $q ) ) wp_send_json_success( [] );
$results = $api->search_read(
'res.partner',
[ '|', [ 'name', 'ilike', $q ], [ 'email', 'ilike', $q ] ],
[ 'id', 'name', 'email', 'is_company' ],
10
);
wp_send_json_success( $results );
}
public static function ajax_link_customer(): void {
check_ajax_referer( 'woodoo_admin', 'nonce' );
if ( ! current_user_can( 'edit_users' ) ) wp_send_json_error( 'Forbidden', 403 );
$user_id = absint( $_POST['user_id'] ?? 0 );
$partner_id = absint( $_POST['partner_id'] ?? 0 );
if ( ! $user_id || ! $partner_id ) wp_send_json_error( 'Invalid IDs' );
$api = woodoo_api();
if ( ! $api ) wp_send_json_error( 'API not configured' );
$partners = $api->read( 'res.partner', [ $partner_id ], [ 'name', 'email' ] );
if ( empty( $partners ) ) wp_send_json_error( 'Partner not found in Odoo' );
update_user_meta( $user_id, 'woodoo_odoo_partner_id', $partner_id );
update_user_meta( $user_id, 'woodoo_odoo_partner_name', sanitize_text_field( $partners[0]['name'] ) );
wp_send_json_success( [
'partner_id' => $partner_id,
'partner_name' => $partners[0]['name'],
] );
}
}