# easy-invoice/2.4.2/includes/Import/SlicedImporter.php

Easy Invoice – Invoice Generator, PDF Quotes &amp; Payments, version 2.4.2. 282 lines.

- Page: https://pluginprobe.com/plugins/easy-invoice/2.4.2/code/includes/Import/SlicedImporter.php
- Raw: https://pluginprobe.com/plugins/easy-invoice/2.4.2/raw/includes/Import/SlicedImporter.php
- Modified: 2026-09-15T12:31:20+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/easy-invoice/2.4.2/code/includes/Import/SlicedImporter.php#L10-L20`.

```php
<?php
/**
 * Import from Sliced Invoices.
 *
 * @package Easy_Invoice
 * @subpackage Import
 */

namespace EasyInvoice\Import;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Sliced keeps quotes and invoices as `sliced_quote` / `sliced_invoice` posts,
 * status as a taxonomy term, line items and payments as arrays of arrays in
 * post meta, and clients as WordPress users with `_sliced_client_*` meta. All
 * of it is readable from here whether or not Sliced is still active; only
 * the posts need to exist.
 *
 * Read from Sliced 3.9's model (`Sliced_Shared::get_totals()`): items live in
 * `_sliced_items[0]`, each with qty / title / description / amount / tax
 * (which is the per-line "adjust %", not tax) / taxable ('on'); payments in
 * `_sliced_payment[0]` with amount / date / gateway / status ('success' means
 * completed). The document-level rate is `_sliced_tax`; the discount
 * `_sliced_discount` with `_sliced_discount_type` 'amount' or 'percentage'.
 */
class SlicedImporter extends Importer {

    public function source(): string {
        return 'sliced';
    }

    public function label(): string {
        return __( 'Sliced Invoices', 'easy-invoice' );
    }

    public function available(): bool {
        return $this->count( 'sliced_invoice' ) + $this->count( 'sliced_quote' ) > 0;
    }

    public function preview(): array {
        $invoices = $this->ids( 'sliced_invoice' );
        $quotes   = $this->ids( 'sliced_quote' );
        $already  = 0;
        foreach ( $invoices as $id ) {
            if ( $this->alreadyImported( \EasyInvoice\Constants\PostTypes::EASY_INVOICE_POST_TYPE, (string) $id ) ) {
                $already++;
            }
        }
        foreach ( $quotes as $id ) {
            if ( $this->alreadyImported( \EasyInvoice\Constants\PostTypes::EASY_INVOICE_QUOTE_POST_TYPE, (string) $id ) ) {
                $already++;
            }
        }
        $clients  = [];
        $payments = 0;
        foreach ( array_merge( $invoices, $quotes ) as $id ) {
            $c = (int) get_post_meta( $id, '_sliced_client', true );
            if ( $c > 0 ) {
                $clients[ $c ] = true;
            }
        }
        foreach ( $invoices as $id ) {
            $payments += count( $this->payments( $id ) );
        }

        return [
            'clients'  => count( $clients ),
            'invoices' => count( $invoices ),
            'quotes'   => count( $quotes ),
            'payments' => $payments,
            'already'  => $already,
        ];
    }

    public function run(): array {
        foreach ( $this->ids( 'sliced_quote' ) as $id ) {
            $this->importQuote( $id );
        }
        foreach ( $this->ids( 'sliced_invoice' ) as $id ) {
            $this->importInvoice( $id );
        }
        return $this->report();
    }

    /**
     * One Sliced invoice.
     *
     * @param int $id Sliced post id.
     * @return void
     */
    private function importInvoice( int $id ): void {
        $d           = $this->document( $id, 'invoice' );
        $d['status'] = $this->invoiceStatus( $id );
        $d['due_date'] = $this->toDate( get_post_meta( $id, '_sliced_invoice_due', true ) );

        $invoice_id = $this->createInvoice( $d );
        if ( $invoice_id <= 0 ) {
            return;
        }
        foreach ( $this->payments( $id ) as $i => $p ) {
            $status = (string) ( $p['status'] ?? '' );
            $this->createPayment( $invoice_id, [
                'source_id'      => $id . ':' . $i,
                'amount'         => $this->toNumber( $p['amount'] ?? 0 ),
                'date'           => $this->toDateTime( $p['date'] ?? '' ) ?: get_post_field( 'post_date', $id ),
                'method'         => (string) ( $p['gateway'] ?? 'imported' ),
                'transaction_id' => (string) ( $p['payment_id'] ?? '' ),
                'status'         => 'success' === $status ? 'completed' : ( 'refunded' === $status ? 'refunded' : 'pending' ),
                'notes'          => (string) ( $p['memo'] ?? '' ),
            ] );
        }
    }

    /**
     * One Sliced quote.
     *
     * @param int $id Sliced post id.
     * @return void
     */
    private function importQuote( int $id ): void {
        $d                = $this->document( $id, 'quote' );
        $d['status']      = $this->quoteStatus( $id );
        $d['expiry_date'] = $this->toDate( get_post_meta( $id, '_sliced_quote_valid_until', true ) );
        $this->createQuote( $d );
    }

    /**
     * The fields both types share, normalised.
     *
     * @param int    $id   Sliced post id.
     * @param string $kind 'invoice' or 'quote'.
     * @return array
     */
    private function document( int $id, string $kind ): array {
        $post      = get_post( $id );
        $src_user  = get_userdata( (int) get_post_meta( $id, '_sliced_client', true ) ) ?: null;
        $client_id = $this->client( (int) get_post_meta( $id, '_sliced_client', true ) );
        $created   = $this->toDateTime( get_post_meta( $id, '_sliced_' . $kind . '_created', true ) ) ?: $post->post_date;

        $items = [];
        $raw   = get_post_meta( $id, '_sliced_items', true );
        // Normally [ [ item, item, … ] ]; older sites stored the list directly.
        $rows = [];
        if ( is_array( $raw ) ) {
            $rows = ( isset( $raw[0] ) && is_array( $raw[0] ) && ! isset( $raw[0]['title'] ) && ! isset( $raw[0]['amount'] ) ) ? $raw[0] : $raw;
        }
        foreach ( $rows as $row ) {
            if ( ! is_array( $row ) ) {
                continue;
            }
            $items[] = [
                'name'              => (string) ( $row['title'] ?? '' ),
                'description'       => wp_strip_all_tags( (string) ( $row['description'] ?? '' ) ),
                'quantity'          => $this->toNumber( $row['qty'] ?? 1 ),
                'price'             => $this->toNumber( $row['amount'] ?? 0 ),
                'adjust_percentage' => $this->toNumber( $row['tax'] ?? 0 ),
                'taxable'           => ( $row['taxable'] ?? '' ) === 'on',
            ];
        }

        $tax = get_post_meta( $id, '_sliced_tax', true );
        $tax = is_array( $tax ) ? ( $tax[0] ?? 0 ) : $tax;


        return [
            'source_id'        => (string) $id,
            'title'            => (string) $post->post_title,
            'number'           => (string) get_post_meta( $id, '_sliced_number', true ),
            'issue_date'       => $this->toDate( get_post_meta( $id, '_sliced_' . $kind . '_created', true ) ) ?: substr( $post->post_date, 0, 10 ),
            'created'          => $created,
            'client_id'        => $client_id,
            'customer_name'    => $src_user ? ( (string) get_user_meta( $src_user->ID, '_sliced_client_business', true ) ?: $src_user->display_name ) : '',
            'customer_email'   => $src_user ? $src_user->user_email : '',
            'customer_address' => $src_user ? (string) get_user_meta( $src_user->ID, '_sliced_client_address', true ) : '',
            'items'            => $items,
            'tax_rate'         => $this->toNumber( $tax ),
            'discount_type'    => 'percentage' === get_post_meta( $id, '_sliced_discount_type', true ) ? 'percentage' : 'fixed',
            'discount_value'   => $this->toNumber( get_post_meta( $id, '_sliced_discount', true ) ),
            'currency_code'    => strtoupper( (string) get_post_meta( $id, '_sliced_currency', true ) ),
            'notes'            => wp_strip_all_tags( (string) get_post_meta( $id, '_sliced_description', true ) ),
            'terms'            => wp_strip_all_tags( (string) get_post_meta( $id, '_sliced_' . $kind . '_terms', true ) ),
        ];
    }

    /**
     * Map a Sliced client user to ours.
     *
     * @param int $user_id Sliced client user id.
     * @return int
     */
    private function client( int $user_id ): int {
        if ( $user_id <= 0 ) {
            return 0;
        }
        $user = get_userdata( $user_id );
        if ( ! $user ) {
            return 0;
        }
        list( $first, $last ) = $this->splitName( $user->display_name );
        return $this->findOrCreateClient( [
            'source_id'  => (string) $user_id,
            'email'      => $user->user_email,
            'first_name' => $user->first_name ?: $first,
            'last_name'  => $user->last_name ?: $last,
            'business'   => (string) get_user_meta( $user_id, '_sliced_client_business', true ),
            'address'    => (string) get_user_meta( $user_id, '_sliced_client_address', true ),
            'extra_info' => (string) get_user_meta( $user_id, '_sliced_client_extra_info', true ),
        ] );
    }

    /**
     * Sliced status term → ours.
     *
     * @param int $id Sliced invoice.
     * @return string
     */
    private function invoiceStatus( int $id ): string {
        $terms = wp_get_object_terms( $id, 'invoice_status', [ 'fields' => 'slugs' ] );
        $slug  = is_array( $terms ) && ! empty( $terms ) ? $terms[0] : 'draft';
        $map   = [ 'draft' => 'draft', 'unpaid' => 'available', 'paid' => 'paid', 'overdue' => 'available', 'cancelled' => 'cancelled' ];
        return $map[ $slug ] ?? 'available';
    }

    /**
     * Sliced quote status term → ours.
     *
     * @param int $id Sliced quote.
     * @return string
     */
    private function quoteStatus( int $id ): string {
        $terms = wp_get_object_terms( $id, 'quote_status', [ 'fields' => 'slugs' ] );
        $slug  = is_array( $terms ) && ! empty( $terms ) ? $terms[0] : 'draft';
        $map   = [ 'draft' => 'draft', 'sent' => 'sent', 'accepted' => 'accepted', 'declined' => 'declined', 'cancelled' => 'declined' ];
        return $map[ $slug ] ?? 'available';
    }

    /**
     * Payment rows of a Sliced invoice.
     *
     * @param int $id Sliced invoice.
     * @return array
     */
    private function payments( int $id ): array {
        $raw = get_post_meta( $id, '_sliced_payment', true );
        if ( is_array( $raw ) && isset( $raw[0] ) && is_array( $raw[0] ) && ! isset( $raw[0]['amount'] ) ) {
            $raw = $raw[0];
        }
        return is_array( $raw ) ? array_values( array_filter( $raw, 'is_array' ) ) : [];
    }

    /**
     * Ids of a Sliced post type.
     *
     * @param string $type Post type.
     * @return int[]
     */
    private function ids( string $type ): array {
        return array_map( 'intval', get_posts( [
            'post_type'      => $type,
            'post_status'    => [ 'publish', 'draft', 'pending', 'private', 'future' ],
            'fields'         => 'ids',
            'posts_per_page' => -1,
            'orderby'        => 'ID',
            'order'          => 'ASC',
        ] ) );
    }

    /**
     * How many of a Sliced post type exist.
     *
     * @param string $type Post type.
     * @return int
     */
    private function count( string $type ): int {
        global $wpdb;
        return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = %s AND post_status NOT IN ('trash','auto-draft')", $type ) );
    }
}

```
