Μετάβαση στο περιεχόμενο

Early-bird άδεια εφ’ όρου ζωής: $199 εφάπαξ, μόνο για τους πρώτους 200 αγοραστές. Δείτε την προσφορά

Απόδειξη ή τιμολόγιο στο ταμείο

Ο πελάτης επιλέγει απόδειξη ή τιμολόγιο. Για τιμολόγιο συμπληρώνει επωνυμία, ΑΦΜ (με έλεγχο), ΔΟΥ και δραστηριότητα. Τα στοιχεία αποθηκεύονται με την παραγγελία και εμφανίζονται στη διαχείριση, στα email της παραγγελίας και στη σελίδα της παραγγελίας.

  • Τύπος PHP
  • Εκτελείται Παντού (εκτελείται καθώς φορτώνει το WordPress)
  • Χρειάζεται WooCommerce
  • Δοκιμασμένο με WordPress 7.1, WooCommerce 11.1
PHP
<?php

// Labels are in Greek; change them if you like.
$fields = array(
	'sf_invoice_company'    => 'Επωνυμία εταιρείας',
	'sf_invoice_vat'        => 'ΑΦΜ',
	'sf_invoice_tax_office' => 'ΔΟΥ',
	'sf_invoice_activity'   => 'Δραστηριότητα',
);

// A Greek VAT number (ΑΦΜ): 9 digits with a check digit.
$valid_vat = static function ( string $vat ): bool {
	if ( ! preg_match( '/^\d{9}$/', $vat ) || '000000000' === $vat ) {
		return false;
	}
	$sum = 0;
	for ( $i = 0; $i < 8; $i++ ) {
		$sum += (int) $vat[ $i ] * ( 2 ** ( 8 - $i ) );
	}
	return ( $sum % 11 ) % 10 === (int) $vat[8];
};

add_filter(
	'woocommerce_checkout_fields',
	static function ( $checkout ) use ( $fields ) {
		$checkout['billing']['sf_document'] = array(
			'type'     => 'radio',
			'label'    => 'Παραστατικό',
			'options'  => array(
				'receipt' => 'Απόδειξη',
				'invoice' => 'Τιμολόγιο',
			),
			'default'  => 'receipt',
			'required' => true,
			'class'    => array( 'form-row-wide', 'sf-document' ),
			'priority' => 5,
		);
		$priority = 6;
		foreach ( $fields as $key => $label ) {
			$checkout['billing'][ $key ] = array(
				'type'     => 'text',
				'label'    => $label . ' <abbr class="required" title="υποχρεωτικό">*</abbr>',
				'required' => false, // Required for invoices only: checked below.
				'class'    => array( 'form-row-wide', 'sf-invoice-field' ),
				'priority' => $priority++,
			);
		}
		return $checkout;
	}
);

add_action(
	'woocommerce_after_checkout_validation',
	static function ( $data, $errors ) use ( $fields, $valid_vat ) {
		if ( 'invoice' !== ( $data['sf_document'] ?? '' ) ) {
			return;
		}
		foreach ( $fields as $key => $label ) {
			if ( '' === trim( (string) ( $data[ $key ] ?? '' ) ) ) {
				$errors->add( 'validation', sprintf( 'Συμπληρώστε το πεδίο «%s» για το τιμολόγιο.', $label ) );
			}
		}
		$vat = preg_replace( '/\D/', '', (string) ( $data['sf_invoice_vat'] ?? '' ) );
		if ( '' !== $vat && ! $valid_vat( $vat ) ) {
			$errors->add( 'validation', 'Ο ΑΦΜ δεν είναι έγκυρος.' );
		}
	},
	10,
	2
);

add_action(
	'woocommerce_checkout_create_order',
	static function ( $order, $data ) use ( $fields ) {
		$document = 'invoice' === ( $data['sf_document'] ?? '' ) ? 'invoice' : 'receipt';
		$order->update_meta_data( '_sf_document', $document );
		if ( 'invoice' === $document ) {
			foreach ( array_keys( $fields ) as $key ) {
				$value = (string) ( $data[ $key ] ?? '' );
				$order->update_meta_data( '_' . $key, 'sf_invoice_vat' === $key ? preg_replace( '/\D/', '', $value ) : sanitize_text_field( $value ) );
			}
		}
	},
	10,
	2
);

// The details, as HTML or plain text.
$details = static function ( $order, bool $plain = false ) use ( $fields ): string {
	if ( ! $order instanceof WC_Order || ! $order->get_meta( '_sf_document' ) ) {
		return '';
	}
	$lines = array( 'Παραστατικό' => 'invoice' === $order->get_meta( '_sf_document' ) ? 'Τιμολόγιο' : 'Απόδειξη' );
	if ( 'invoice' === $order->get_meta( '_sf_document' ) ) {
		foreach ( $fields as $key => $label ) {
			$lines[ $label ] = (string) $order->get_meta( '_' . $key );
		}
	}
	$out = '';
	foreach ( $lines as $label => $value ) {
		$out .= $plain ? $label . ': ' . $value . "\n" : '<strong>' . esc_html( $label ) . ':</strong> ' . esc_html( $value ) . '<br>';
	}
	return $plain ? "\n" . $out : '<p class="sf-invoice-details">' . $out . '</p>';
};

add_action(
	'woocommerce_admin_order_data_after_billing_address',
	static function ( $order ) use ( $details ) {
		echo $details( $order ); // phpcs:ignore WordPress.Security.EscapeOutput -- Escaped above.
	}
);

// The order page for customers: classic templates show it with the
// customer's details, block themes in the thank-you page's extra information.
$show_once = static function ( $order ) use ( $details ) {
	static $shown = array();
	$order = $order instanceof WC_Order ? $order : wc_get_order( $order );
	if ( $order && empty( $shown[ $order->get_id() ] ) ) {
		$shown[ $order->get_id() ] = true;
		echo $details( $order ); // phpcs:ignore WordPress.Security.EscapeOutput -- Escaped above.
	}
};
add_action( 'woocommerce_order_details_after_customer_details', $show_once );
add_action( 'woocommerce_thankyou', $show_once, 20 );
add_action(
	'woocommerce_email_after_order_table',
	static function ( $order, $sent_to_admin = false, $plain_text = false ) use ( $details ) {
		echo $plain_text ? esc_html( $details( $order, true ) ) : $details( $order ); // phpcs:ignore WordPress.Security.EscapeOutput -- Escaped above.
	},
	10,
	3
);

// Show the invoice fields only when "Τιμολόγιο" is picked.
add_action(
	'wp_footer',
	static function () {
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || is_order_received_page() ) {
			return;
		}
		?>
		<style>.sf-invoice-field .optional{display:none}.sf-document .woocommerce-input-wrapper label{display:inline;margin:0 1em 0 .3em}</style>
		<script>
		jQuery( function ( $ ) {
			var toggle = function () {
				$( '.sf-invoice-field' ).toggle( $( 'input[name="sf_document"]:checked' ).val() === 'invoice' );
			};
			$( document.body ).on( 'change', 'input[name="sf_document"]', toggle );
			toggle();
		} );
		</script>
		<?php
	}
);

Καλό να ξέρετε

Για το κλασικό ταμείο (το shortcode [woocommerce_checkout] ή το μπλοκ Classic Checkout). Τα στοιχεία αποθηκεύονται ως πεδία της παραγγελίας (_sf_document, _sf_invoice_vat…), που μπορούν να τα διαβάσουν πρόσθετα τιμολόγησης και εξαγωγές.

Σε αυτά τα πακέτα

  • Ελληνικό e-shop: Για καταστήματα στην Ελλάδα: απόδειξη ή τιμολόγιο με έλεγχο ΑΦΜ, έλεγχος ελληνικών τηλεφώνων και ταχυδρομικών κωδικών, χρέωση αντικαταβολής και διευθύνσεις σε greeklish.

Μεταφέρετε τα snippets σας μέσα σε ένα απόγευμα.

Η εισαγωγή δεν αλλάζει τίποτα μέχρι να κάνετε τη μετάβαση, και τα παλιά σας shortcodes συνεχίζουν να λειτουργούν.