/** * Copyright (C) 2014-2023 ServMask Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗ * ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝ * ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝ * ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗ * ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗ * ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ */ if ( ! function_exists( 'ai1wmve_clear_scheduled_events' ) ) { /** * Clears all scheduled events for selected storage type * If $extension is null then it clears ALL the events * * @param $extension */ function ai1wmve_clear_scheduled_events( $extension = null ) { $events = new Ai1wmve_Schedule_Events(); $events->clear( $extension ); } } if ( ! function_exists( 'ai1wmve_is_running' ) ) { /** * Check whether export/import is running * * @return boolean */ function ai1wmve_is_running() { if ( isset( $_GET['file'] ) || isset( $_POST['file'] ) ) { return true; } return false; } } if ( ! function_exists( 'ai1wmve_reset_db_backup_path' ) ) { /** * Get db-options-backup.json absolute path * * @return string */ function ai1wmve_reset_db_backup_path() { return AI1WM_STORAGE_PATH . DIRECTORY_SEPARATOR . AI1WMVE_RESET_DB_BACKUP; } } /** * Copyright (C) 2014-2023 ServMask Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗ * ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝ * ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝ * ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗ * ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗ * ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ */ if ( ! defined( 'ABSPATH' ) ) { die( 'Kangaroos cannot jump here' ); } class Ai1wm_Export_Content { public static function execute( $params ) { // Set archive bytes offset if ( isset( $params['archive_bytes_offset'] ) ) { $archive_bytes_offset = (int) $params['archive_bytes_offset']; } else { $archive_bytes_offset = ai1wm_archive_bytes( $params ); } // Set file bytes offset if ( isset( $params['file_bytes_offset'] ) ) { $file_bytes_offset = (int) $params['file_bytes_offset']; } else { $file_bytes_offset = 0; } // Set content bytes offset if ( isset( $params['content_bytes_offset'] ) ) { $content_bytes_offset = (int) $params['content_bytes_offset']; } else { $content_bytes_offset = 0; } // Get processed files size if ( isset( $params['processed_files_size'] ) ) { $processed_files_size = (int) $params['processed_files_size']; } else { $processed_files_size = 0; } // Get total content files size if ( isset( $params['total_content_files_size'] ) ) { $total_content_files_size = (int) $params['total_content_files_size']; } else { $total_content_files_size = 1; } // Get total content files count if ( isset( $params['total_content_files_count'] ) ) { $total_content_files_count = (int) $params['total_content_files_count']; } else { $total_content_files_count = 1; } // What percent of files have we processed? $progress = (int) min( ( $processed_files_size / $total_content_files_size ) * 100, 100 ); // Set progress Ai1wm_Status::info( sprintf( __( 'Archiving %d content files...
%d%% complete', AI1WM_PLUGIN_NAME ), $total_content_files_count, $progress ) ); // Flag to hold if file data has been processed $completed = true; // Start time $start = microtime( true ); // Get content list file $content_list = ai1wm_open( ai1wm_content_list_path( $params ), 'r' ); // Set the file pointer at the current index if ( fseek( $content_list, $content_bytes_offset ) !== -1 ) { // Open the archive file for writing $archive = new Ai1wm_Compressor( ai1wm_archive_path( $params ) ); // Set the file pointer to the one that we have saved $archive->set_file_pointer( $archive_bytes_offset ); // Loop over files while ( list( $file_abspath, $file_relpath, $file_size, $file_mtime ) = fgetcsv( $content_list ) ) { $file_bytes_written = 0; // Add file to archive if ( ( $completed = $archive->add_file( $file_abspath, $file_relpath, $file_bytes_written, $file_bytes_offset ) ) ) { $file_bytes_offset = 0; // Get content bytes offset $content_bytes_offset = ftell( $content_list ); } // Increment processed files size $processed_files_size += $file_bytes_written; // What percent of files have we processed? $progress = (int) min( ( $processed_files_size / $total_content_files_size ) * 100, 100 ); // Set progress Ai1wm_Status::info( sprintf( __( 'Archiving %d content files...
%d%% complete', AI1WM_PLUGIN_NAME ), $total_content_files_count, $progress ) ); // More than 10 seconds have passed, break and do another request if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) { if ( ( microtime( true ) - $start ) > $timeout ) { $completed = false; break; } } } // Get archive bytes offset $archive_bytes_offset = $archive->get_file_pointer(); // Truncate the archive file $archive->truncate(); // Close the archive file $archive->close(); } // End of the content list? if ( feof( $content_list ) ) { // Unset archive bytes offset unset( $params['archive_bytes_offset'] ); // Unset file bytes offset unset( $params['file_bytes_offset'] ); // Unset content bytes offset unset( $params['content_bytes_offset'] ); // Unset processed files size unset( $params['processed_files_size'] ); // Unset total content files size unset( $params['total_content_files_size'] ); // Unset total content files count unset( $params['total_content_files_count'] ); // Unset completed flag unset( $params['completed'] ); } else { // Set archive bytes offset $params['archive_bytes_offset'] = $archive_bytes_offset; // Set file bytes offset $params['file_bytes_offset'] = $file_bytes_offset; // Set content bytes offset $params['content_bytes_offset'] = $content_bytes_offset; // Set processed files size $params['processed_files_size'] = $processed_files_size; // Set total content files size $params['total_content_files_size'] = $total_content_files_size; // Set total content files count $params['total_content_files_count'] = $total_content_files_count; // Set completed flag $params['completed'] = $completed; } // Close the content list file ai1wm_close( $content_list ); return $params; } } /** * Common functions. * * @package Yoast\WP\Duplicate_Post * @since 2.0 */ use Yoast\WP\Duplicate_Post\Permissions_Helper; use Yoast\WP\Duplicate_Post\UI\Link_Builder; use Yoast\WP\Duplicate_Post\Utils; /** * Tests if post type is enabled to be copied. * * @param string $post_type The post type to check. * @return bool */ function duplicate_post_is_post_type_enabled( $post_type ) { $duplicate_post_types_enabled = get_option( 'duplicate_post_types_enabled', [ 'post', 'page' ] ); if ( ! is_array( $duplicate_post_types_enabled ) ) { $duplicate_post_types_enabled = [ $duplicate_post_types_enabled ]; } /** This filter is documented in src/permissions-helper.php */ $duplicate_post_types_enabled = apply_filters( 'duplicate_post_enabled_post_types', $duplicate_post_types_enabled ); return in_array( $post_type, $duplicate_post_types_enabled, true ); } /** * Template tag to retrieve/display duplicate post link for post. * * @param int $id Optional. Post ID. * @param string $context Optional, default to display. How to write the '&', defaults to '&'. * @param bool $draft Optional, default to true. * @return string */ function duplicate_post_get_clone_post_link( $id = 0, $context = 'display', $draft = true ) { $post = get_post( $id ); if ( ! $post ) { return ''; } $link_builder = new Link_Builder(); $permissions_helper = new Permissions_Helper(); if ( ! $permissions_helper->should_links_be_displayed( $post ) ) { return ''; } if ( $draft ) { return $link_builder->build_new_draft_link( $post, $context ); } else { return $link_builder->build_clone_link( $post, $context ); } } /** * Displays duplicate post link for post. * * @param string|null $link Optional. Anchor text. * @param string $before Optional. Display before edit link. * @param string $after Optional. Display after edit link. * @param int $id Optional. Post ID. */ function duplicate_post_clone_post_link( $link = null, $before = '', $after = '', $id = 0 ) { $post = get_post( $id ); if ( ! $post ) { return; } $url = duplicate_post_get_clone_post_link( $post->ID ); if ( ! $url ) { return; } if ( $link === null ) { $link = __( 'Copy to a new draft', 'duplicate-post' ); } $link = '' . esc_html( $link ) . ''; /** * Filter on the clone link HTML. * * @param string $link The full HTML tag of the link. * @param int $ID The ID of the post. * * @return string */ echo $before . apply_filters( 'duplicate_post_clone_post_link', $link, $post->ID ) . $after; // phpcs:ignore WordPress.Security.EscapeOutput } /** * Gets the original post. * * @param int|null $post Optional. Post ID or Post object. * @param string $output Optional, default is Object. Either OBJECT, ARRAY_A, or ARRAY_N. * @return mixed Post data. */ function duplicate_post_get_original( $post = null, $output = OBJECT ) { return Utils::get_original( $post, $output ); } Kolb Consulting https://kolb-handwerker-consulting.com Stefan Kolb Tue, 30 Apr 2024 12:55:26 +0000 de hourly 1 https://wordpress.org/?v=6.7.1 https://kolb-handwerker-consulting.com/wp-content/uploads/2024/04/favicon.png Kolb Consulting https://kolb-handwerker-consulting.com 32 32 Die 7 Fehler, die Dich als Handwerker im Hamsterrad gefangen halten https://kolb-handwerker-consulting.com/die-7-fehler-die-dich-als-handwerker-im-hamsterrad-gefangen-halten-schlechte-ergebnisse-zahlen-nicht-im-griff-fachkraeftemangel-und-wenn-du-an-die-betriebsnachfolge-denkst-bekommst-du-ein-ungute/ Thu, 25 Apr 2024 13:02:39 +0000 https://kolb-handwerker-consulting.com/?p=1261

– schlechte Ergebnisse, Zahlen nicht im Griff, Fachkräftemangel und wenn Du an die Betriebsnachfolge denkst, bekommst Du ein ungutes Gefühl

Ursachen für das Hamsterrad im Handwerk:

Handwerker sind im Hamsterrad – das sagen mir 9 von 10 Handwerkern in persönlichen Gesprächen.

Aus über 25 Jahren Erfahrung habe ich mehrere Ursachen dafür identifiziert und fasse diese für Dich hier zusammen.

  1. Im Handwerk ist die Mischkalkulation gebräuchlich, das heisst der Stundensatz ist in der Regel zu niedrig und wird über Materialaufschlag “subventioniert”. Das führt an vielen Stellen zu Risiken für die Handwerker und oftmals kennen die Chefs diese Risiken nicht einmal, weil sie davon ausgehen, dass sie “richtig” kalkulieren. Die Folge ist, dass auf dem Papier die Dinge in Ordnung aussehen, auf dem Konto sieht es dann manchmal anders aus. 
  2. Die Auftragslage für fast alle Handwerker ist gut bis sehr gut. Dies führt in der Regel zu “Stress”, weil jeder Kunde/Auftrag schnellstens bedient werden muss – ist das wirklich so und muss das so bleiben? Vielen Betrieben fehlt der strategische Ansatz, was man bevorzugt macht und… was NICHT!!! Aus Nachkalkulationen lassen sich klare Empfehlungen für die Ausrichtung des Betriebs ableiten. Dies führt zu besseren Ergebnisse auf Projekt- und Betriebsebene. Bessere Ergebnisse können auch zu besseren Mitarbeiterergebnissen führen, weil z Bsp Erfolgsbeteiligungen möglich werden.
  3. In vielen Handwerksbetrieben wachsen die Umsätze schneller als die Abläufe, Systeme und die Digitalisierung. Das ist kein Vorwurf, sondern nur eine Feststellung. Langfristig macht das die Betriebe für neue und junge Mitarbeiter unattraktiv. Für einen möglichen Betriebs-Nachfolger ist es nicht ratsam, sich einen Betrieb zu nehmen, wo der bisherige Chef alles kann und weiss. Aus meiner Erfahrung sollte ab 7 Mitarbeitern mit der Einführung von festen Abläufen (=Systeme), Digitalisierung und zwischenzeitlich auch mit dem Thema “Künstliche Intelligence im Handwerk” begonnen werden. Wer das heute nicht tun kann oder will, wird es später noch schwerer haben, sich am Markt erfolgreich zu etablieren und als Arbeitgeber attraktiv zu sein. Dies wirkt sich natürlich auf den Unternehmenswert aus. Du kannst raten, in welche Richtung….
  4. Viele Handwerksbetriebe verkaufen noch über den Preis. Dabei wären viele Kunden bereit, “etwas mehr für das Bad / die Heizung / …” zu bezahlen. Und, es ist auch im ersten Schritt für den Handwerker ganz einfach, sich positiv von den Mitbewerbern zu unterscheiden: 1. Halte deine zugesagten Termine beim Kunden ein (egal ob Angebotsabgabe, Beginn Baustelle, Ende Baustelle,…) und 2. Halte Deine Budgets (Kaufpreis) ein – mit diesen beiden Maßnahmen bist Du vermutlich schon besser als die meisten Deiner Kollegen und… diese Maßnahmen kosten Dich keinen Cent. Gleichzeitig baust Du Dir ein wesentlich besseres Image am Markt und damit bei deinen Kunden auf, welche das auch mit höheren Preisen honorieren.
  5. In der Regel bearbeiten die Handwerker (fast) alle Kundenanfragen – ohne Selektion, ohne Strategie. Dies führt zu viel Arbeit und hohen Betriebsauslastungen. In vielen Fällen wäre das Motto “Weniger ist Mehr” besser: soll heißen, mit weniger Umsatz mehr Ergebnisse erzielen. Wenn Du die betriebswirtschaftlich besten Anfragen sofort erkennst, diese Anfragen bevorzugt und sorgfältig bearbeitest und die nicht rentablen “freundlich” ablehnst oder für DICH rentabel anbietest, hast Du ein besseres Leben und mehr Zeit, Dich im die richtigen Kunden und beste Mitarbeiter zu kümmern  – versprochen !!!
  6. Viele Handwerksbetriebe haben ihre laufenden Projekte im Griff: Materialbestellungen, Personaleinteilungen, Termin mit Kunden abstimmen,… aber: betriebswirtschaftlich hapert es gewaltig. Die Bewertung der “Halbfertigen Arbeiten” und die Übersicht über die erhaltenen Abschlagszahlungen vom Kunden sind für die Qualität der BWA und die Liquidität des Betriebs enorm wichtig. Am besten machst Du das über Deine Software (Eingangsrechnungen, Stunden der eigenen Monteure, Abschlagszahlungen,..) auf die Projekte erfassen und schon hast Du alle Kennzahlen für das laufende / wöchentliche Projektcontrolling im Griff und einmal im Monat gibt“ einen Buchungsbeleg für den Steuerberater, so dass Deine BWA endlich aussagekräftig ist. Kein Blindflug mehr.
  7. Das Hamsterrad – viele Handwerker-Chefs haben schlichtweg nicht die Zeit und oftmals auch nicht die Plan und die Unterstützung, um AM Unternehmen zu arbeiten und damit aus ihrem Hamsterrad zu entkommen. Ich sag Dir aber  was: wenn Du immer das gleiche tust und dabei andere Ergebnisse erwartest… Wahnsinn.

Du brauchst also einen klaren Fahrplan und einen Mentor / Coach an Deiner Seite. Das schafft zum einen Klarheit, was getan werden muss und andererseits Verbindlichkeiten, die Dinge umzusetzen.

]]>